using generics without changing the class header - java

Lets say I have two classes. Pair:
public class Pair<X, Y> {
public X x;
public Y y;
public Pair(X x , Y y) {
this.x = x;
this.y = y;
}
}
and the class Triple:
public class Triple<X, Y, Z> {
public X x;
public Y y;
public Z z;
public Triple(X x , Y y, Z z) {
this.x = x;
this.y = y;
this.z = z;
}
}
And I want to create a class Test without changing the class header (can't do Test<X, Y, Z>):
public class Test {
...
}
In this class should be a method, that takes a list of Triples and should return a Map with the x-value of the triple as a key and the y and z-values of the triple as the value of the map.
How can I do this without changing the class header?

You can do it. You need to make the method generic rather than the class it's in.
class Test {
static <X, Y, Z> Map<X, Pair<Y, Z>> makeMap(List<Triple<X, Y, Z>> triples) {
// your implementation
}
}
The method could be static or non-static. In either case, the generic parameters <X, Y, Z> appear immediately before the return type.

From your description, here an implementation:
public static <X, Y, Z> Map<X, Pair<Y, Z>> makeMap(List<Triple<X, Y, Z>> arg) {
return arg.stream().collect(Collectors.toMap(e -> e.x, e -> new Pair<>(e.y, e.z)));
}

Related

Objects override each other

I have the class GameObject:
public class GameObject{
private Coordinate coordinates;
public GameObject(){
coordinates = new Coordinate();
}
public void setCoordinates(int x, int y){
coordinates.x = x;
coordinates.y = y;
}
//More methods here
}
public class Coordinate{
public int x, y;
public Coordinate(){
}
public Coordinate(int x, int y){
this.x = x;
this.y = y;
}
public void setCoordinate(int x, int y){
this.x = x;
this.y = y;
}
And two classes Champion and Spell:
public class Spell extends GameObject{
//Some methods
}
public class Champion extends GameObject{
//Some methods
public Spell fireBall = new Spell();
}
And in my main class:
Champion character = new Champion();
If I call character.setCoordinates(200, 300); (just random numbers), the character goes to these exact coordinates. But the Spell fireBall also goes to (200, 300). So the coordinates in Spell are overriden by the setCoordinates(int x, int y) call to character. How is this possible?
TL;DR - Two classes from GameObject, Spell extends GameObject and Champion extends GameObject, override eachother coordinates. Why?
For full source code:
GameObject.java
Spell.java
Champion.java
Coordinate.java
Looking at your code in gitHub you have 2 methods:
//Set the coordinates for this GameObject
public void setCoordinates(int x, int y){
this.coordinates.x = x;
this.coordinates.y = y;
}
public void setCoordinates(Coordinate coordinates){
this.coordinates = coordinates;
}
If you ever use the 2nd one, then you are sharing the same instance of Coordinates so changing one will change the other
The solution is to copy the values instead
public void setCoordinates(Coordinate coordinates){
this.coordinates.x = coordinates.x;
this.coordinates.y = coordinates.y;
}
In the class Spell you set the coordinates:
this.startCoordinates = startCoordinates;
setCoordinates(this.startCoordinates);
Subsequently this code
if (getCoordinates().x - startCoordinates.x < range) {
is equivalent to
if (getCoordinates().x - getCoordinates().x < range) {
because getCoordinates() references the same object as startCoordinates does.
Your setter method just sets the reference, but it does not copy the object.

Generic behaviour

(sorry for the pun)
Say one wants to define a generic builder, like this:
public abstract class GenericBuilder<T extends Product> {
int x;
int y;
<K extends GenericBuilder<T>> K setX(int x) {
this.x = x;
return (K)this;
}
<K extends GenericBuilder<T>> K setY(int y) {
this.y = y;
return (K) this;
}
abstract T build();
}
abstract class Product {
int x;
int y;
}
class ConcreteProduct extends Product {
int z;
}
class ConcreteBuilder extends GenericBuilder<ConcreteProduct>{
int z;
<K extends GenericBuilder<ConcreteProduct>> K setZ(int z) {
this.z = z;
return (K) this;
}
#Override
ConcreteProduct build() {
ConcreteProduct cp = new ConcreteProduct();
cp.x = x;
cp.y = y;
cp.z = z;
return cp;
}
public static void main(String[] args) {
new ConcreteBuilder().setX(1).setY(2).setZ(3);
}
}
When calling ConcreteBuilder.setZ(), it fails during compilation.
Why is that? Is it due erasure? Or the generics, say, don't carry information about its generic parameters?
EDIT:
Any ideas how to avoid using second generic parameter in:
public class ConcreteBuilder extends GenericBuilder<ConcreteProduct, ConcreteBuilder>
i.e. <..., ConcreteBuilder>, which seems to be a little clumsy? I guess it's not possible. Are there other languages (C# maybe?) which allow to do that?
Break your code this way and you will understand that your class GenericBuilder<ConcreteProduct> doesn't have any setZ() method defined.
GenericBuilder<ConcreteProduct> setY = new ConcreteBuilder().setX(1).setY(2);
setY.setZ(3);
In your GenericBuilder your functions return a GenericBuilder when you don't specify the type argument of the function. In your main function the call to setX returns a GenericBuilder and you loose the information that you are actually using a ConcreteBuilder. To succesfully make the calls, you have to specify the generic parameters for the setters:
new ConcreteBuilder().<ConcreteBuilder>setX(1).<ConcreteBuilder>setY(2).setZ(3);
Alternative
You can add a second type parameter to GenericBuilder:
public abstract class GenericBuilder<T extends Product, K extends GenericBuilder<T, K>> {
int x;
int y;
K setX(int x) {
this.x = x;
return (K)this;
}
K setY(int y) {
this.y = y;
return (K) this;
}
abstract T build();
}
and change ConcreteBuilder to this:
public class ConcreteBuilder extends GenericBuilder<ConcreteProduct, ConcreteBuilder> {
int z;
ConcreteBuilder setZ(int z) {
this.z = z;
return this;
}
#Override
public ConcreteProduct build() {
ConcreteProduct cp = new ConcreteProduct();
cp.x = x;
cp.y = y;
cp.z = z;
return cp;
}
public static void main(String[] args) {
new ConcreteBuilder().setX(1).setY(2).setZ(3);
}
}

error: constructor Miclass in class Miclass cannot be applied to given types;

I'm trying to compile this in java and get this error: error: constructor Miclass in class Miclass cannot be applied to given types.
what's happening?
class Miclass {
public int x;
private int y;
protected int z;
public Miclass(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
}
public class A extends Miclass {
public static void main(String [] args) {
Miclass m_class = new Miclass(2, 4, 8);
System.out.println("m_class.x = " + m_class.x);
System.out.println("m_class.y = " + m_class.y);
System.out.println("m_class.z = " + m_class.z);
}
}
As there is already a constructor defined in Miclass you need to add a constructor in A that invokes this constructor in the super-class:
public class A extends Miclass {
public A(int x, int y, int z) {
super(x, y, z);
}
// methods/fields specific to `A`
...
}
The code will not compile after this change as the variable y is not visible to A. To allow the code to compile you can add a getter method to access the variable.
I have correct your code, try this, and read my explanation after..
class Miclass {
public int x;
private int y;
protected int z;
public Miclass(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public int getY()
{
return y;
}
}
public class A {
public static void main(String [] args) {
Miclass m_class = new Miclass(2, 4, 8);
System.out.println("m_class.x = " + m_class.x);
System.out.println("m_class.y = " + m_class.getY());
System.out.println("m_class.z = " + m_class.z);
}
}
Java provides default no-arg constructor only when there is no other constructor defined
In this case you have defined a constructor with 3 int arguments for class Miclass and you have not called it from class A which extends Miclass
due to this, when a default no-argument constructor will be provided to A class, a call to super no-argument will be done which is not possible because you do not have a no-argument constructor in Miclass
to solve these issues you will either have to create a no-arg constructor in superclass or create a constructor with 3 int arguments.
also your variable is not visible in class A because private variables are visible only in the same class

How can I use a 'next generation' java data object style together with interfaces?

I'm writing most of my immutable data objects in the following style, which is somtimes described as 'next generation' or 'functional':
public class Point {
public final int x;
public final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
I would like to use the same style for data objects specified by interfaces:
public interface Point {
public final int x;
public final int y;
}
public class MyPoint {
public MyPoint(int x, int y) {
this.x = x;
this.y = y;
}
}
public class Origin {
public Origin() {
this.x = 0;
this.y = 0;
}
}
But this is not allowed by java, which gives an error in the interface code as well as the implementations.
I can change my code to
public interface Point {
public int x();
public int y();
}
public class MyPoint {
private int mx, my;
pulic MyPoint(int x, int y) {
mx = x;
my = y;
}
public int x() {return mx;}
public int y() {return my;}
}
public class Origin {
public int x() {return 0;}
public int y() {return 0;}
}
But it is more code, and I don't think it gives nearly the same feeling of simplicity in the API.
Can you see a path out of my dilemma? Or do you personally use a third, even simpler style?
(I'm not really interested in a discussion of mutable/immutable, getterSetter/new-style or private/public fields.)
I would rather switch to use inheritance or delegation
public class Point {
public final int x;
public final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
Inheritance
public class MyPoint extends Point {
public MyPoint (int x, int y) {
super (x, y);
}
....
}
public class Origin extends Point {
public Origin () {
super (0, 0);
}
}

Defining an enum in Java

I have a class in Java describing a parameter (name: Param) and another class in which I declare and initialize around 100 of such parameters as:
private static final Param param_name_1 = new Param(x, y, z);
I would like to put all these objects/instances in an enum and initialize them there. What is the best method to do that?
===UPDATE===
I asked for the syntax of the enum but not like that.
I my case Param is another java class which has its own parameters, getters and setters and a constructor with the 3 parameters between the paranthesis:
public Param(intx, int y, int z){
this.x = x;
this.y = y;
this.z = z;
}
I my other class I declare and initialize 100 instances of the class Param as written above. Each x, y and z for each instance are different.
And the enum should contain the declaration of the instances and possibly also initialize them.
Assuming that you're asking about the enum syntax then you can do something like this (assuming that x, y and z are compile time constants).
public enum Param {
param_name_1(1,2,3),
param_name_2(3,4,5);
private int x;
private int y;
private int z;
private Param(int x, int y, int z) {
this.x=x;
this.y=y;
this.z=z;
}
}
An enum is a special type of class, so you can declare constructors, fields and methods as well as implement interfaces. However, they can not extend other classes.
In this case, I'd suggest final fields and getters, like this:
public enum Param {
PARAM_A(1, 2, 3),
PARAM_B(4, 5, 6),
PARAM_C(1, 3, 5);
private final int x;
private final int y;
private final int z;
private Param(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
}
I think this is what you want
class Param
{
private int x, y, z;
public Param(int x, int y, int z)
{
this.x = x; this.y = y; this.z = z;
}
}
public class t
{
private enum ParamVals
{
VAL1(new Param(0,0,0)),
VAL2(new Param(1,1,1));
private Param paramVal;
private ParamVals(Param paramVal)
{
this.paramVal = paramVal;
}
public Param getVal()
{
return paramVal;
}
}
}

Categories

Resources