I'm coming from C++ and I'm trying to inherit the Generic parameter type in Java. Basically, I'm trying to emulate the below C++ pattern:
In C++, I can do:
#include <iostream>
class Node
{
Node* next;
};
class BaseVisitor
{
public:
BaseVisitor(Node* ptr)
{
std::cout<<ptr<<"\n\n";
delete ptr;
}
~BaseVisitor() {};
protected:
virtual Node* Generate() = 0;
};
class DynamicVisitor : public BaseVisitor
{
public:
DynamicVisitor(Node* ptr) : BaseVisitor(ptr) {}
protected:
virtual Node* Generate()
{
std::cout<<"Dynamic Visitor\n";
return new Node();
}
};
class StaticVisitor : public BaseVisitor
{
public:
StaticVisitor(Node* ptr) : BaseVisitor(ptr) {}
protected:
virtual Node* Generate()
{
std::cout<<"Static Visitor\n";
return NULL;
}
};
template<typename T>
class TestVisitor : public T //THIS is where the magic happens..
{
public:
TestVisitor() : T(this->Generate()) {} //allows me to call "Generate".
};
int main()
{
TestVisitor<DynamicVisitor> foo = TestVisitor<DynamicVisitor>();
TestVisitor<StaticVisitor> bar = TestVisitor<StaticVisitor>();
}
Output:
Dynamic Visitor
0x605ed0
Static Visitor
NULL
How can I do the same thing in Java? I tried:
public class Node {
Node next;
}
public abstract class BaseVisitor {
public BaseVisitor(Node n) {System.out.println(n);}
protected abstract Node generate();
}
public class DynamicVisitor extends BaseVisitor {
public DynamicVisitor(Node n) {
super(n);
}
#Override
protected Node generate() {
return new Node();
}
}
public class StaticVisitor extends BaseVisitor {
public StaticVisitor(Node n) {
super(n);
}
#Override
protected Node generate() {
return null;
}
}
public class TestVisitor<T extends BaseVisitor> extends T { //error.. Cannot extend "T".. No magic happens..
public TestVisitor() {
super(this.generate()); //cannot call generate()..
}
}
What is this pattern called? I call it "Base Factory" pattern but I'm not sure the real name for it so I wasn't sure what to search for..
How can I do the same thing as in C++, in Java? Is there "any way" to do the same pattern in Java?
Nope, can't do this in java, sorry. The closest is, probably, a "delegate pattern":
public interface NodeGenerator { Node generate(); }
public class StaticGenerator implements NodeGenerator {
public Node generate() { return null; }
}
public class DynamicGenerator implements NodeGenerator {
public Node generate() { return new Node(); }
}
public class TestVisitor extends BaseVisitor {
public TestVisitor(NodeGenerator g) { super(g.generate()); }
}
In java 8, you can make this look nicer (but possibly less efficient), without the extra interfaces and classes:
public class TestVisitor extends BaseVisitor {
public TestVisitor(Supplier<Node> g) { super(g.get()); }
}
// ... and then you can do things like
TestVisitor staticVisitor = new TestVisitor(() -> null);
TestVisitor dynamicVisitor = new TestVisitor(() -> new Node());
Related
I created a java project to apply my GraphTheory course and enhance my java skills.
In this project :
I created a class Sommet<S>(Vertex in English) with an attribute Id with a generic type called <S>.
I created a class Arc<S>(Edge in English) with two attributes Sommet(Vertex).
I created a class EnsembleArc which is an HashSet of Arc
I also created a class ArcValue which inherit from Arc and have an int attribute Valeur(Value in English)
Here everything is fine and I dont have any problem.
But then I created a class EnsembleArcValue which inherit from EnsembleArc because every method from EnsembleArc will be useful to EnsembleArcValue.
But I also want EnsembleArcValue to be an HashSet of ArcValue (and I dont want an Arc which is not an ArcValue). And with the inheritance EnsembleArcValue is able to have an "simple" Arc in his Set.
So my question after all this explanation is :
Is there a way for EnsembleArcValue to inherit from EnsembleArc but will only accept an ArcValue in his Set.
Here is an image of The UML Project
I hope it will help to understand my problem (dont look at the bottom).
Here is the code :
public class Sommet<S>
{
//attributes
private S id;
public Sommet(S s)
{
setId(s);
}
public S getId()
{
return id;
}
public void setId(S s)
{
assert s!= null: "Objet null passé en paramètre";
id = s;
}
#SuppressWarnings("unchecked")
#Override
public boolean equals(Object obj)
{
boolean callback;
if(obj.getClass()!=getClass())
{
callback=false;
}
else
{
if(((Sommet<S>)obj).getId().equals(getId()))
{
callback=true;
}
else
{
callback=false;
}
}
return callback;
}
#Override
public int hashCode()
{
return getId().hashCode();
}
#Override
public String toString()
{
return getId().toString();
}
}
public class Arc<S>
{
private Sommet<S> depart;
private Sommet<S> arrivee;
public Arc(Sommet<S> dep, Sommet<S> arr)
{
setDepart(dep);
setArrivee(arr);
}
#Override
public String toString()
{
String str="("+getDepart().getId()+","+getArrivee().getId()+")";
return str;
}
public Sommet<S> getDepart()
{
return depart;
}
public Sommet<S> getArrivee()
{
return arrivee;
}
public void setDepart(Sommet<S> depart)
{
this.depart = depart;
}
public void setArrivee(Sommet<S> arrivee)
{
this.arrivee = arrivee;
}
#SuppressWarnings("unchecked")
#Override
public boolean equals(Object obj)
{
boolean callback;
if(obj.getClass()!=getClass())
{
callback=false;
}
else
{
if(((Arc<S>)obj).getDepart().equals(getDepart())&&((Arc<S>)obj).getArrivee().equals(getArrivee()))
{
callback=true;
}
else
{
callback=false;
}
}
return callback;
}
#Override
public int hashCode()
{
return getArrivee().hashCode()+getDepart().hashCode();
}
}
public class ArcValue<S,V> extends Arc<S>
{
private V valeur;
public ArcValue (Sommet<S> depart, Sommet<S> arrivee, V valeur)
{
super(arrivee,depart);
this.valeur=valeur;
}
public V getValeur()
{
return valeur;
}
}
import java.util.HashSet;
public class Ensemble<E> extends HashSet<E> implements Cloneable
{
private static final long serialVersionUID = -4354387895748449845L;
public Ensemble ()
{
super();
}
public Ensemble (Ensemble<E> ensemble)
{
for (E e : ensemble)
{
add(e);
}
}
public String toString()
{
StringBuffer str=new StringBuffer("{");
for(E e: this)
{
str=str.append(e.toString()+",");
}
str.setCharAt(str.length()-1, '}');
return str.toString();
}
#SuppressWarnings("unchecked")
#Override
public Ensemble<E> clone()
{
return (Ensemble<E>)super.clone();
}
}
public class EnsembleArc<S> extends Ensemble<Arc<S>>
{
public EnsembleArc(Ensemble<Arc<S>> ensemble)
{
super(ensemble);
}
public EnsembleArc()
{
super();
}
private static final long serialVersionUID = -4099925554493145279L;
public EnsembleSommet<S> listSucc(Sommet<S> sommet)
{
EnsembleSommet<S> XSucc=new EnsembleSommet<S>();
for (Arc<S> arc : this)
{
if (arc.getDepart()==sommet)
{
XSucc.add(arc.getArrivee());
}
}
return XSucc;
}
public EnsembleSommet<S> listPred(Sommet<S> sommet)
{
EnsembleSommet<S> XPred=new EnsembleSommet<S>();
for (Arc<S> arc : this)
{
if (arc.getArrivee()==sommet)
{
XPred.add(arc.getDepart());
}
}
return XPred;
}
public void add(Sommet<S> depart,Sommet<S>arrivee)
{
add(new Arc<S>(depart,arrivee));
}
#Override
public EnsembleArc<S> clone ()
{
return (EnsembleArc<S>)super.clone();
}
}
//import java.util.Collection;
public class EnsembleArcValues<S,V> extends EnsembleArc<S> //implements Collection<ArcValue<S,V>>
{
//TODO faire en sorte que ensembleArcValués ne contienne que des ArcsValue
private static final long serialVersionUID = -7163498825360866323L;
}
And you'll need this one to :
public class EnsembleSommet<S> extends Ensemble<Sommet<S>>
{
public EnsembleSommet()
{
super();
}
public EnsembleSommet(EnsembleSommet<S> ensemble)
{
super(ensemble);
}
private static final long serialVersionUID = 7278825382690341067L;
#Override
public EnsembleSommet<S> clone ()
{
return (EnsembleSommet<S>)super.clone();
}
public Sommet<S> firstSommet()
{
#SuppressWarnings("unchecked")
Sommet<S>[] tab=new Sommet[size()];
return toArray(tab)[0];
}
}
The only way you can achieve this is to make the type of Arc you want part of your generic deceleration. Rename your existing EnsembleArc to AbstractEnsembleArc and change it's generic decleration from < S > to < S, T extends Arc< S > > i.e.:
public abstract class AbstractEnsembleArc<S, T extends Arc<S>> extends Ensemble<T> {
// PUT ALL YOUR LOGIC CURRENTLY IN EnsembleArc HERE
}
Now create a new Class Called EnsembleArc and extend the new abstract class you've added, this new class will work identically to your existing EnsembleArc and class decleration should now look like:
public class EnsembleArc<S> extends AbstractEnsembleArc<S, Arc<S>> {
}
Finally have EnsembleArcValues extend the Abstract class instead of EnsembleArc so that you can declare that it should only accepts ArcValue and not simple Arc, do that like this:
public class EnsembleArcValues<S, V> extends AbstractEnsembleArc<S, ArcValue<S, V>> {
}
I got some problem with java's interfaces and abstract classes.
I have interface
public interface IVector <T extends IVector>{
public IVector add(IVector vector);
public IVector sub(IVector vector);
public double dotProduct(IVector vector);
public IVector scalar(double scalar);
}
and abstract class like this:
public abstract class Vector implements IVector{
final ArrayList<Double> coordinates;
public Vector(ArrayList<Double> list){
coordinates = list;
}
public IVector add(Vector v){
ArrayList<Double> newCoordinates = new ArrayList<>();
if (v.coordinates.size() == this.coordinates.size()){
for (int i = 0; i < this.coordinates.size(); i++) {
newCoordinates.add(v.coordinates.get(i)+this.coordinates.get(i));
}
}
else return null;
return new IVector(newCoordinates);
}
Its just addition of vectors with n coordinates, how can i return result? I wanna use child classes (like 2dVector or 3dVector) in future?
You cannot create an abstract object directly - you need concrete class or override the required methods defined by the abstract.
Something like this may be what you are looking for.
public interface IVector<T extends IVector> {
public T add(T vector);
public T sub(T vector);
public double dotProduct(T vector);
public T scalar(double scalar);
}
public abstract class Vector<T extends Vector> implements IVector<T> {
final ArrayList<Double> coordinates;
public Vector(ArrayList<Double> list) {
coordinates = list;
}
}
public class AVector extends Vector<AVector> {
public AVector(ArrayList<Double> list) {
super(list);
}
#Override
public AVector add(AVector v) {
ArrayList<Double> newCoordinates = new ArrayList<>();
if (v.coordinates.size() == this.coordinates.size()) {
for (int i = 0; i < this.coordinates.size(); i++) {
newCoordinates.add(v.coordinates.get(i) + this.coordinates.get(i));
}
} else return null;
return new AVector(newCoordinates);
}
#Override
public AVector sub(AVector vector) {
return null;
}
#Override
public double dotProduct(AVector vector) {
return 0;
}
#Override
public AVector scalar(double scalar) {
return null;
}
}
Note that using public abstract class Vector implements IVector in your code introduces Raw Types and should be avoided. Notice I have used public abstract class Vector<T extends Vector> implements IVector<T> instead.
To achieve your aim of making the add method generic to all Vector objects as you seem to be trying to do you need some form of factory method.
Something like this may be a fair attempt at that.
public interface IVector<T extends IVector> {
public T add(T vector);
}
public interface Factory<T> {
public T makeNew (ArrayList<Double> coordinates);
}
public abstract class Vector<T extends Vector<T> & Factory<T>> implements IVector<T> {
final ArrayList<Double> coordinates;
public Vector(ArrayList<Double> list) {
coordinates = list;
}
#Override
public T add(T v) {
if (v.coordinates.size() == this.coordinates.size()) {
ArrayList<Double> newCoordinates = new ArrayList<>();
for (int i = 0; i < this.coordinates.size(); i++) {
newCoordinates.add(v.coordinates.get(i) + this.coordinates.get(i));
}
// Use the passed parameter as a factory.
return v.makeNew(coordinates);
}
return null;
}
}
public class AVector extends Vector<AVector> implements Factory<AVector> {
public AVector(ArrayList<Double> list) {
super(list);
}
#Override
public AVector makeNew(ArrayList<Double> coordinates) {
return new AVector(coordinates);
}
}
An abstract class cannot be instantiated: nor can an interface. You have to return either a subclass of Vector or an implementation of IVector.
I have a problem with the different type of objects in a collection, in that case ArrayList, here there is an example:
public interface CustomObject {}
public class CustomObjectA implements CustomObjects {}
public class CustomObjectB implements CustomObjects {}
In the main I call myMethod:
ArrayList<CustomObject> list = new ArrayList<>();
for(int i=0; i < list.size(); i++) {
myMethod(list.get(i));
}
myMethod is defined with an overloading as written below:
public void myMethod(CustomObjectA a) { ... }
public void myMethod(CustomObjectB b) { ... }
There is a compile-error. How can I solve? What's the right way to it (Collections, generics, wildcard ?)
One way to work around this is the use of the visitor pattern, which allows you to attach functionality, without touching your domain objects
// A visitor, which can 'visit' all your types
interface CustomObjectVisitor {
void visitA(CustomObjectA a);
void visitB(CustomObjectB b);
}
// Make CustomObject a visitee
public interface CustomObject {
void accept(CustomObjectVisitor visitor);
}
// Implement the classes with the accept method
public class CustomObjectA implements CustomObject {
#Override public void accept(CustomObjectVisitor visitor) {
visitor.visitA(this);
}
}
public class CustomObjectB implements CustomObject {
#Override public void accept(CustomObjectVisitor visitor) {
visitor.visitB(this);
}
}
Now you can make your Main class a visitor like this:
public class Main implements CustomObjectVisitor {
public void methodThatDidntWorkBefore() {
ArrayList<CustomObject> list = new ArrayList<>();
for(CustomObject obj: list) {
obj.accept(this);
}
}
#Override public void visitA(CustomObjectA a) { ... }
#Override public void visitB(CustomObjectB b) { ... }
}
Check out WikiPedia too, it's really useful once you wrap your head around it.
With:
public interface CustomObject { void myMethod(); }
public class CustomObjectA implements CustomObjects {
#Override
public void myMethod() {...}
}
public class CustomObjectB implements CustomObjects {
#Override
public void myMethod() {...}
}
Then:
ArrayList<CustomObject> list = new ArrayList<>();
for(int i=0; i < list.size(); i++) {
list.get(i).myMethod(); // invoke dynamic
}
Which will execute the method corresponding to what the object's dynamic type is.
e.g. If get(i) returns an object with a dynamic type of CustomObjectA it will execute CustomObjectA::myMethod.
You could try something like this:
public class myMethodClass {
public static void main(String[] args) {
ArrayList<CustomObject> list = new ArrayList<>();
for(int i=0; i < list.size(); i++) {
myMethod(list.get(i));
}
}
public static void myMethod(CustomObject o){
if(o instanceof CustomObjectA) myMethod((CustomObjectA) o);
if(o instanceof CustomObjectB) myMethod((CustomObjectB) o);
}
public static void myMethod(CustomObjectA a) { }
public static void myMethod(CustomObjectB b) { }
}
interface CustomObject {}
class CustomObjectA implements CustomObject {}
class CustomObjectB implements CustomObject {}
I have a class called Point, with a method neighbors() that returns an array of Points:
public class Point {
public Point[] neighbors() { /* implementation not shown */ }
}
I have a subclass of Point, called SpecialPoint that overrides neighbors() to return an array of SpecialPoints instead of Points. I think this is called covariant return types.
public class SpecialPoint extends Point {
public SpecialPoint[] neighbors() { /* implementation not shown */ }
}
In a separate class, I want to make use of Point and SpecialPoint with generics
public <P extends Point> P doStuff(P point) {
P[] neighbors = point.neighbors();
// more stuff here including return
}
This will not compile, because the compiler can only guarantee that P is some subclass of Point, but there is no guarantee that every subclass of Point will override neighbors() to return an array of itself as I happen to have done with SpecialPoint, so Java only knows that P#neighbors() returns Point[], not P[].
How do I guarantee that each subclass overrides neighbors() with a covariant return type so I can use it with generics?
You may use an interface:
public interface Point<P extends Point<P>> {
P[] neighbors();
}
public class SimplePoint implements Point<SimplePoint> {
#Override
public SimplePoint[] neighbors() { /* ... */ }
}
public class SpecialPoint implements Point<SpecialPoint> {
#Override
public SpecialPoint[] neighbors() { /* ... */ }
}
Then:
public <P extends Point<P>> P doStuff(P point) {
P[] neighbors = point.neighbors();
/* ... */
}
If you still need to factorize code between the implementations, then better use an abstract class:
public abstract class Point<P extends Point<P>> {
public abstract P[] neighbors();
public void commonMethod() { /* ... */ }
}
public class SimplePoint extends Point<SimplePoint> { /* ... */ }
public class SpecialPoint extends Point<SpecialPoint> { /* ... */ }
Possibly an interface Point solves your problem:
public class Test
{
public interface Point {
public Point[] neighbors();
}
public class SpecialPoint implements Point {
public SpecialPoint[] neighbors() { return null; }
}
public class SpecialPoint2 implements Point {
public SpecialPoint2[] neighbors() { return null; }
}
public Point doStuff(SpecialPoint point) {
Point[] neighbors = point.neighbors();
return neighbors[0];
}
public Point doStuff(SpecialPoint2 point) {
Point[] neighbors = point.neighbors();
return neighbors[0];
}
}
I have a problem with the generic use I suppose,
Some code:
public class ObservableValue<T> extends Observable {
private T value;
public ObservableValue(T initial) {
setValue(initial);
}
public void setValue(T newValue) {
if (value != newValue) {
this.value = newValue;
setChanged();
notifyObservers(value);
}
}
}
public class SokobanGame implements Game, Observer {
protected final ArrayList<GameStatusBarElement<Integer>> windowElements;
public void nextLevel(Integer currentLevel){
this.windowElements.get(0).getElement().setValue(currentLevel);
for(GameStatusBarElement<Integer> element : windowElements)
element.update();
}
}
public class GameStatusBarElement<T> {
protected final ObservableValue<T> element;
public GameStatusBarElement(String elementText,
ObservableValue<T> observableValue) {
this.element = observableValue;
}
}
And that in the main implementation :
GameStatusBarElement<Integer> level = new GameStatusBarElement<Integer>("Level:", new ObservableValue<Integer>(1));
GameWindow gameWindow = new GameWindow("",
null, null, level);
}
So, the problem is: I cannot use setValue(currentLevel) (in SokobanGame) because of the currentLevel type, eclipse tell me to put something with the T type... But I instantiate the class of this.windowElements.get(0).getElement() with new GameStatusBarElement<Integer>("Level:", new ObservableValue<Integer>(1));, so I don't understand what's the problem ?
Everything seems fine, but I don't see the implementation of your getElement() method.
If your getElement() method is like this one:
public ObservableValue<T> getElement() {
return element;
}
it should compile just fine.