2014-05-23 9 views
15

Ich versuche, eine abstrakte Range-Klasse zu definieren, die als Basisimplementierung einer Reihe von Bereichsklassen dienen wird. Die bestimmungsgemäße Verwendung ist für diese Frage irrelevant, aber bisher habe ich:Abstrakte Klasse mit Standardwert

/** 
* Abstract generic utility class for handling ranges 
*/ 
public abstract class Range<T extends Number> { 

    // Variables to hold the range configuration 
    private T start; 
    private T stop; 
    private T step; 

    /** 
    * Constructs a range by defining it's limits and step size. 
    * 
    * @param start The beginning of the range. 
    * @param stop The end of the range. 
    * @param step The stepping 
    */ 
    public Range(T start, T stop, T step) { 
    this.start = start; 
    this.stop = stop; 
    this.step = step; 
    } 
} 

Jetzt habe ich mit einen Konstruktor hinzufügen möchten, dass dauert nur start und stop und setzt einen Standard-Schrittwert von 1, egal, was die Umsetzung von NumberT ist (zB wenn T ist Integer[one] würde den Wert 1, und wenn T ist Long[one] würde den Wert 1L, und so weiter haben). Ich möchte so etwas wie:

protected Range(T start, T stop) { 
    this(start, stop, [one]); 
} 

aber ich kann nicht herausfinden, wie so den Wert von [one] eingestellt. Da Java mir noch ziemlich neu ist, habe ich versucht, mit:

private static final T one = 1; 

, die nicht funktioniert, weil T offensichtlich in der Instanziierung Range.this definiert ist. Ich habe auch versucht:

protected static abstract T getOne(); 

das auch nicht funktioniert, weil T in der Instanziierung Range.this definiert ist und static und abstract nicht zusammen arbeiten.

Ich brauche eine Möglichkeit für die Erweiterung von Klassen gezwungen werden, den Wert [one] zu definieren, egal welche Implementierung von NumberRange implementiert ist.

Letztendlich würde ich auch einen Nullwert als Standard-Start setzen wollen, so dass ich einen Konstruktor, der wie folgt aussieht:

protected Range(T stop) { 
    this([zero], stop, [one]); 
} 
+2

Ich bin mir sicher, Nummer ist die richtige Oberklasse zu verwenden. Es gibt interessante Fragen zu diesem Thema: http://stackoverflow.com/questions/2721390/how-to-add-two-java-lang-numbers - Ich meine, auch wenn Sie das herausfinden, wie würden Sie den Schritt hinzufügen Beginnen Sie, über den Bereich zu iterieren? –

+1

'this (start, stop, (T) (neue Ganzzahl (1)));' –

Antwort

15

Eine Lösung wäre, die Unterklassen für den Standard Schritt zu fragen, zu verwenden, :

public abstract class Range<T extends Number> { 

    private T start; 
    private T stop; 
    private T step; 

    public Range(T start, T stop, T step) { 
     this.start = start; 
     this.stop = stop; 
     this.step = step; 
    } 

    protected Range(T start, T stop) { 
     this.start = start; 
     this.stop = stop; 
     this.step = getDefaultStep(); 
    } 

    protected abstract T getDefaultStep(); 

} 

public class IntegerRange extends Range<Integer> { 

    public IntegerRange(Integer start, Integer stop, Integer step) { 
     super(start, stop, step); 
    } 

    public IntegerRange(Integer start, Integer stop) { 
     super(start, stop); 
    } 

    @Override 
    protected Integer getDefaultStep() { 
     return 1; 
    } 

} 

public class DoubleRange extends Range<Double> { 

    public DoubleRange(Double start, Double stop, Double step) { 
     super(start, stop, step); 
    } 

    public DoubleRange(Double start, Double stop) { 
     super(start, stop); 
    } 

    @Override 
    protected Double getDefaultStep() { 
     return 1d; 
    } 

} 
+0

Boom! +1 für die schnelle Antwort. –

+1

Ich zweite, dass, obwohl jede implementierende Klasse einen Standardschritt bereitstellen muss, unabhängig davon, ob es nicht einmal den kurzen Konstruktor verwendet. – Smutje

+0

Sie können das nicht tun. 'Range.getDefaultStep' kann nicht aufgerufen werden, bevor' Range' instanziiert wurde und daher nicht im Konstruktor verwendet werden kann. – beruic

5

Sie diese Implementierung verwenden können:

protected Range(T start, T stop) { 
    this(start, stop, (T) (new Integer(1))); 
} 
+0

Kann 'Integer' in die anderen Unterklassen von' Number' wie 'Double' umgewandelt werden? – awksp

+0

Ja; es könnte umgewandelt werden. –

+3

Huh, das ist interessant ... Warum sollte diese Umwandlung erfolgreich sein, wenn eine explizite Umwandlung wie 'Double d = (Double) new Integer (1);' nicht einmal kompiliert wird? – awksp

2

Sie laufen in andere Probleme ... aber hier ist Ihre Nummer 1:

Number ONE = new Number() { 
    @Override 
    public int intValue() { 
     return 1; 
    } 

    @Override 
    public long longValue() { 
     return 1L; 
    } 

    @Override 
    public float floatValue() { 
     return 1.0f; 
    } 

    @Override 
    public double doubleValue() { 
     return 1.0; 
    } 

    @Override 
    public byte byteValue() { 
     return 1; 
    } 

    @Override 
    public short shortValue() { 
     return 1; 
    } 
}; 
+0

Möchten Sie auf die anderen Probleme näher eingehen? :) – beruic

+0

Es wäre interessant zu sehen, wie Sie den Bereich in generischer Weise durchlaufen werden, ich meine, fügen Sie den "Schritt" zum "Start" und compapre es mit "Stop". Sie können verlangen, dass die Unterklassen Ihnen 'compare (T, T)', 'add (T, T)' usw. zur Verfügung stellen, aber es sieht nicht gut aus IMHO :) Andererseits sehe ich keine bessere Lösung. .. –

+0

Sie können das vergleichbare Problem mit Range lösen , die arithmetischen Operationen werden immer noch schmerzhaft sein –