2010-01-04 18 views
3

J'ai défini deux classes ci-dessous:comment appeler la méthode sans connaître le nom de la classe?

public class junk { 
    private BigInteger a = BigIngeger.valueOf(1), b=BigInteger.valueOf(2), c; 

    public void DoSomething() { 
     c = a.add(b); 
    } 

    // ... other stuff here 
} 

public class junkChild extends junk { 
    private BigDecimal a = BigDecimal.valueOf(1), b=BigDecimal.valueOf(2), c; 
    // I want a, b, c to override the original BigInteger a,b,c 
    // ... other stuff here 
}  

public class myClass { 
    public static void main(String args[]) { 
     junk a1 = new junkChild(); 
     a1.DoSomething(); 
    } 
} 

Malheureusement ne fonctionne pas au-dessus.

Ce que je veux faire est de changer simplement a, b, c-BigDecimal en junkChild sans réécrire DoSomething() à nouveau. Même si je dois l'écrire à nouveau, le code sera exactement le même, donc il devrait y avoir un moyen de faire ce travail sans avoir à l'écrire. La fonction DoSomething doit vérifier que le type a1 a une méthode add du type d'entrée et de retour correct, et si c'est le cas, l'invoquer sans se soucier du type a, b, c.

Est-ce que cela peut être fait?

+0

Vous devriez lire à la réflexion. Cela répondra à la deuxième partie de votre question. Comme pour la première partie, n'utilisez pas directement les champs 'a',' b' et 'c', mais utilisez plutôt les méthodes' getA', 'getB', et' getC' que vous substituez dans les sous-classes. –

+0

On dirait que ce que vous voulez vraiment, ce sont des modèles de type C++. –

+2

On dirait qu'il veut vraiment "taper du canard". – Asaph

Répondre

4

Non, vous ne pouvez pas le faire - du moins pas lors de la compilation. Les deux méthodes add sont effectivement sans rapport - elles ne proviennent pas d'une interface ou quelque chose comme ça.

Vous pouvez le faire avec la réflexion (après l'ajout de propriétés pour a, b et c ou quelque chose de similaire - les champs ne peuvent pas être « surchargée » comme ça), mais ce ne serait pas terriblement agréable.

+0

la réponse la plus pointue. Par curiosité, pourquoi faire cela avec 'System.out.print'? (Nous pouvons définir une méthode 'toString' pour n'importe quelle classe arbitraire) – Jus12

+0

@ Jus12:' toString() 'hérite de' Object' dont toutes les classes finissent par hériter. Toute classe peut remplacer 'toString()'. – Asaph

2

La fonction de langage de programmation que vous demandez est appelée duck typing et Java ne la prend pas en charge. Vous devrez suivre votre stratégie de méthode d'emballage d'origine.

1

depuis Nombre (le plus proche ancêtre des deux classes ne pas la méthode add), vous pouvez convertir votre BigInteger BigDecimal premier:

new BigDecimal(bi) 
2

Comme cela a été dit, Java ne le fait pas « canard en tapant "où les deux types ne partagent pas une interface utile. BigDecimal et BigInteger étendent Number, mais la méthode add() ne fait pas partie de cette interface, donc cela n'aide pas.

Je pense que vous devez rendre explicite ce que vous opérez dans les paramètres de méthode de doSomething(). Ensuite, vous pouvez overrride doSomething() pour fonctionner sur les deux types:

public BigDecimal doSomething(BigDecimal a, BigDecimal b) { 
     return a.add(b); 
} 

public BigInteger doSomething(BigInteger a, BigInteger b) { 
    BigDecimal x = new BigDecimal(a); 
    BigDecimal y = new BigDecimal(b); 
    BigDecimal z = doSomething(x, y); 
    return z.toBigInteger(); 
} 

La deuxième méthode est tout simplement une méthode de conversion qui appelle alors la logique réelle dans la première méthode.

+0

J'ai déménagé à Scala depuis. En Scala, ces choses sont si faciles 'def foo [T <: {def add [T] (a: T, b: T): Unité; val a: T}] (barre: T): T = ???' – Jus12