Is it possible to get public static field from template class argument? - java

Given
class A {
public static A newInstance(int x) { ... }
}
And several classes containing static fields of type A
class B1 {
public static A MIN = A.newInstance(10);
}
class B2 {
public static A MIN = A.newInstance(15);
}
I would like to parameterize a class with B1 or B2 to get MIN field of type A from class B in the class C:
class C <T, P> {
private T t = ???;
}
When C<A, B1> c = new C(); what should be placed instead ??? to get B1.MIN?
Is it possible?
EDIT:
Thank you for the answers, I have upvoted both.
I have arrived simply at
class C <T, P> {
private T t;
public C(T min) {
this.t = min;
}
}
This will be just C<A, B1> c = new C<A, B1>(B1.MIN); because as you can see it is hard to avoid a constructor for C taking an instance of B1 or smth like that. But in this case B1 at least not instantiated.

You can use an interface to achieve this behavior:
class A {
public static A newInstance() { return new A(); }
}
interface HasMin {
public static A MIN = null;
}
class B1 implements HasMin {
public static A MIN = A.newInstance();
}
class B2 implements HasMin {
public static A MIN = A.newInstance();
}
class C<T extends HasMin> {
private A t = T.MIN;
}
Then you can create: C<B1> and C<B2> and use both.
As Tom suggested in the comments below, this approach is limited to use static fields. An even better approach would be:
public class Play {
public static void main(String[] args) {
B1 b1 = new B1();
C<B1> c = new C<>(b1);
System.out.println(c.getA()); // prints: A{ x=10 }
B2 b2 = new B2();
C<B2> c2 = new C<>(b2);
System.out.println(c2.getA()); // prints: A{ x=20 }
}
}
class A {
private int x;
public A(int x) {
this.x = x;
}
#Override
public String toString() {
return "A{ x=" + x + " }";
}
public static A newInstance(int x) {
return new A(x);
}
}
interface GetMin {
public A getMin();
}
class B1 implements GetMin {
public A MIN = A.newInstance(10);
#Override
public A getMin() {
return MIN;
}
}
class B2 implements GetMin {
public A MIN = A.newInstance(20);
#Override
public A getMin() {
return MIN;
}
}
class C<T extends GetMin> {
private A a = null;
public C(T t) {
a = t.getMin();
}
public A getA() {
return a;
}
}

I would forget static and have a concrete instance of an interface:
public interface Bounds<T> {
T min();
}
The concrete instance could be singleton, so next best thing to a static:
public enum B implements Bounds<A> {
INSTANCE;
private final A min = A.newInstance(10);
#Override
public A min() {
return min;
}
}
C then defined like so:
public class C<T, P extends Bounds<T>> {
private T min;
public C(P bounds) {
min = bounds.min();
}
public T getMin() {
return min;
}
}
Usage:
C<A, B> c = new C(B.INSTANCE);
Self describing
Maybe you don't want this meta data type (B), maybe you want types to describe themselves. So C could be defined for types that can describe their own bounds:
public class C<T extends Bounds<T>> {
private T min;
public C(T anyT) {
min = anyT.min();
}
public T getMin() {
return min;
}
}
Usage:
C<A> c = new C(A.zero); //any A will do
Where A is:
public class A implements Bounds<A>{
public final static A zero = A.newInstance(0);
private final static A min = A.newInstance(10);
public static A newInstance(int x) {
return new A(x);
}
private int x;
public A(int x) {
this.x = x;
}
#Override
public A min() {
return min;
}
}

Related

Builder pattern with inheritance support generics issue

I implemented pattern based on this answer
I have the following asbtract config:
public abstract class AbstractConfig {
public static abstract class Builder<B extends Builder<B>> {
private int calories = 0;
public Builder() {
}
public B setCalories(int calories) {
this.calories = calories;
return (B) this;
}
public abstract AbstractConfig build();
}
private int calories = 0;
protected AbstractConfig(final Builder builder) {
calories = builder.calories;
}
}
And I have the following concrete config:
public class DialogConfig extends AbstractConfig {
public static class DialogConfigBuilder<B extends DialogConfigBuilder<B>> extends Builder<B> {
private double width;
private double height;
public DialogConfigBuilder() {
//does nothing.
}
public B setWidth(final double value) {
width = value;
return (B) this;
}
public B setHeight(final double value) {
height = value;
return (B) this;
}
public DialogConfig build() {
return new DialogConfig(this);
}
}
private final double width;
private final double height;
protected DialogConfig(final DialogConfigBuilder builder) {
super(builder);
width = builder.width;
height = builder.height;
}
public double getWidth() {
return width;
}
public double getHeight() {
return height;
}
}
And this is how I use it
DialogConfig config = new DialogConfig.DialogConfigBuilder()
.setWidth(0)
.setCalories(0)
.setHeight(0) //X LINE
.build();
At X line I get - Can't find symbol method setHeight. What is my mistake?
EDIT - I will have and a ExtendedDialogConfig that must extend DialogConfig and etc. I mean there will be other subclasses.
You would first change setCalories() to:
public Builder<B> setCalories(int calories) {
this.calories = calories;
return this;
}
to get rid of that cast and the warning. And now look at this closely. You return a Builder. This code doesn't know about future subclasses. It only returns an instance of that base builder.
As a consequence, when you have that chained call:
.setHeight(0) .build();
that would return that base builder. To then call build() - which would build an abstract configuration. But you want to assign that to a more specific DialogConfig. Thus the error.
A (ugly) workaround:
DialogConfig.DialogConfigBuilder<?> builder = new DialogConfig.DialogConfigBuilder<>().setHeight(0);
builder.setCalories(0);
...config = builder.build();
And a solution - by again reworking setCalories():
#SuppressWarnings("unchecked")
public <T extends B> T setCalories(int calories) {
this.calories = calories;
return (T) this;
}
Fixes the compile error; and allows chaining the setCalories() call as well. Final exercise of getting rid of the cast/suppress is left as exercise to the reader.
And for the record - the "complete" solution, including all adaptions to get rid of raw types and other warnings:
abstract class AbstractConfig {
public static abstract class Builder<B extends Builder<B>> {
private int calories = 0;
#SuppressWarnings("unchecked")
public <T extends B> T setCalories(int calories) {
this.calories = calories;
return (T) this;
}
public abstract AbstractConfig build();
}
private int calories = 0;
public int getCalories() { return calories; }
protected <B extends Builder<B>> AbstractConfig(final Builder<B> builder) {
calories = builder.calories;
}
}
final class DialogConfig extends AbstractConfig {
public static class DialogConfigBuilder<B extends DialogConfigBuilder<B>> extends Builder<B> {
private double width;
private double height;
public DialogConfigBuilder<B> setWidth(final double value) {
width = value;
return this;
}
public DialogConfigBuilder<B> setHeight(final double value) {
height = value;
return this;
}
public DialogConfig build() {
return new DialogConfig(this);
}
}
private final double width;
private final double height;
protected <B extends DialogConfigBuilder<B>> DialogConfig(final DialogConfigBuilder<B> builder) {
super(builder);
width = builder.width;
height = builder.height;
}
public double getWidth() { return width; }
public double getHeight() { return height; }
}
public class Builders {
public static void main(String[] args) {
DialogConfig config = new DialogConfig.DialogConfigBuilder<>().setHeight(0).setCalories(0).build();
System.out.println(config);
}
}
I found my mistake. This is how I used DialogConfigBuilder
DialogConfig config = new DialogConfig.DialogConfigBuilder()
.setWidth(0)
.setCalories(0)
.setHeight(0) //X LINE
.build();
This is how I should use DialogConfigBuilder
DialogConfig config = new DialogConfig.DialogConfigBuilder<>()
.setWidth(0)
.setCalories(0)
.setHeight(0) //X LINE
.build();
Pay attention to <> in the second case.

Handling ClassCastException In Different Objects

I'm having a hard time to understand the ClassCastException and it is crashing the line that it is commented. Please explain why its doing in that? Thanks
public class tester {
private static B<Data> build(char[] ss, double[] f) {
B<Data> res = new B<Data>();
PriorityQueue<String> q = new PriorityQueue<String>();
...
double c_x = 20.1;
Data h = res.getElement(); //throws ClassCastException
if(h.getFreq()==c_x){
...
}
}//end of method
}//end of class tester
public class Data{
private char symbol;
private double freq;
public Data(char c, double f){
symbol = c;
freq = f;
}
public char getSymbol(){
return symbol;
}
public double getFreq(){
return freq;
}
public String toString(){
return freq + ":" + symbol;
}
public int compareTo(Data o) {
return (int) (this.freq-o.freq);
}
}//end of class Data
public class B<T> {
// the fields
private T element;
private B<T> left;
private B<T> right;
// create an empty node
public B() {
this(null, null, null);
}
public B(T theElement, B<T> lt, B<T> rt) {
element = theElement;
left = lt;
right = rt;
}
// return the element
public T getElement() {
return element;
}
public void setElement(T x) {
element = x;
}
}//end of class B
Exception:
Exception in thread "main" java.lang.ClassCastException: java.lang.Double cannot be cast to Data
at tester.build(tester.java:40)
at tester.main(tester.java:83)
Do you happen to have some method that takes a raw type B? Because if you do, you can assign any value to element in that method.
Example
static void rawSet(B b) {
b.setElement(1.0); // you can put anything here
}
public static void main(String [] args) {
B<Integer> b = new B<>();
rawSet(b);
Integer x = b.getElement(); // ClassCastException
}
Since you didn't post complete code I could run, I have to make my own.
Data.java:
package test;
public class Data {
private char symbol;
private double freq;
public Data(char c, double f){
symbol = c;
freq = f;
}
public char getSymbol(){
return symbol;
}
public double getFreq(){
return freq;
}
public String toString(){
return freq + ":" + symbol;
}
public int compareTo(Data o) {
return (int) (this.freq-o.freq);
}
}
GenericType.java (replacing B):
package test;
public class GenericType<T> {
private T element;
public GenericType() {
element = null;
}
public T getElement() {
return element;
}
public void setElement(T x) {
element = x;
}
}
Test.java (main program):
package test;
public class Test {
public static void main(String[] args) {
GenericType<Data> obj = new GenericType<Data>();
Data d = obj.getElement();
System.out.println("Data retrieved");
}
}
When executed:
> java test.Test
Data retrieved
So there's a problem somewhere, and you omitted it.
How to create a Minimal, Complete, and Verifiable example
https://stackoverflow.com/help/mcve
Generics is only a compile-time concept. At runtime they are just Objects. Your problem most likely lies in how you instantiate B.

Pass enum class as parameter to method in java

I have two different Enums:
public enum A {
mass(10); // many other values omitted for clarity
private final int m;
private A(int m) { this.m = m; }
public int value() { return this.m; }
}
public enum B {
mass(100); // many other values omitted for clarity
private final int m;
private B(int m) { this.m = m; }
public int value() { return this.m; }
}
and want to pass enum class as parameter to my function. From other answers that I found on SO, it is suggested that I can pass Class, but I am not sure how to correctly detect and use A or B enum in the function body:
public int mass(Class<?> clazz) {
// Is it the best way? How to avoid a bunch of ifs?
if (clazz == A.class) return A.mass.value();
if (clazz == B.class) return B.mass.value();
}
Not sure what you're trying to accomplish buddy but you seem to be in need of polymorphism. Try using an interface with Enums like this:
public enum A implements MassProvider {
MASS(10);
private int mass;
A(int mass) {
this.mass = mass;
}
#Override
public int getMass() {
return mass;
}
}
public enum B implements MassProvider {
MASS(100);
private int mass;
B(int mass) {
this.mass = mass;
}
#Override
public int getMass() {
return mass;
}
}
public interface MassProvider {
int getMass();
}
public static int mass(MassProvider p) {
return p.getMass();
}
Basically instead of passing a class to the mass method you pass a MassProvider that is implemented by both enums.

Java type parameter is not within its bound

I have a class Zeitpunkt which implements a date with time and in addition a class Suchbaum which represents a binary search tree.
I want to use a Comparator-Object in Suchbaum to sort a tree by the day of Zeitpunkt, but when I want to create a Suchbaum object, it prints the named error.
Zeipunkt
public class Zeitpunkt<T> implements Comparable<T>
{
private int jahr;
private int monat;
private int tag;
private int stunden;
private int minuten;
private double sekunden;
public int vergleich(Zeitpunkt a) { ... }
#Override
public int compareTo(T o) {
if(o instanceof Zeitpunkt)
return vergleich((Zeitpunkt)o);
return 0;
}
...
}
Suchbaum
public class Suchbaum<T extends Comparable<T>> {
private class Element {
private T daten;
private Element links;
private Element rechts;
public Element(T t) {
daten = t;
links = null;
rechts = null;
}
}
private Element wurzel;
private Comparator<T> comp;
...
}
Testclass
public class BaumTest {
public static void main(String[] args) {
// error in the following line (IntelliJ underlines the first
// "Zeitpunkt"). Suchbaum<Zeitpunkt<?>> = ... doesn't work either..
// *Completely confused*
Suchbaum<Zeitpunkt> sb = new Suchbaum<>((Zeitpunkt z1, Zeitpunkt z2) -> {
if(z1.getTag() > z2.getTag())
return 1;
else if(z1.getTag() == z2.getTag())
return 0;
else
return -1;
});
}
}
Any ideas? (the other threads with this topic didn't help me out)
Seems that you don't want to make your Zeitpunkt class parametrized, you just want it to implement Comparable interface. So change it like this:
public class Zeitpunkt implements Comparable<Zeitpunkt> {
private int jahr;
private int monat;
private int tag;
private int stunden;
private int minuten;
private double sekunden;
public int vergleich(Zeitpunkt a) {
return 0;
}
#Override
public int compareTo(Zeitpunkt o) {
return vergleich(o);
}
}
Also you need to define a constructor in your Suchbaum class:
public Suchbaum(Comparator<T> comp) {
this.comp = comp;
}

extend class issue when creating new object

There's something wrong in my code, but i don't know why. I have two class:
public class MyClass extends MySuperClass {
potected int field1;
public MyClass() {
super();
}
#Override
public int getField1() {
return this.field1;
}
public void setField1(int f) {
this.field1 = f;
}
}
public class MySuperClass {
potected int field1, field2;
public MySuperObject() {
}
public int getField1() {
return this.field1;
}
public void setField1(int f) {
this.field1 = f;
}
public void setField2(int f) {
this.field2 = f;
}
public int getField2() {
return this.field2;
}
}
When i create different new MyClass object (i.e. for insert inside an ArrayList) something go wrong:
ArrayList<MyClass> list = new ArrayList<MyClass>();
while(condidion) {
MyClass obj = new MyClass();
obj.setField1(value1);
obj.setField2(value2);
list.add(obj);
}
If value1 and value2 assume the sequent value
1 and 50
2 and 70
3 and 80
After my code is executed, my list contains
1 and 80
2 and 80
3 and 80
It looks like that every time i create new MyClass object, only an instance of MySuperClass it's created (field2 assume the value of last input value).
How can i fix it?
Here is the code which you have given. It is working perfectly if you give correct input.
import java.util.ArrayList;
class MyClass extends MySuperClass {
protected int field1;
public MyClass() {
super();
}
#Override
public int getField1() {
return this.field1;
}
public void setField1(int f) {
this.field1 = f;
}
}
class MySuperClass {
protected int field1, field2;
public MySuperClass() {
}
public int getField1() {
return this.field1;
}
public void setField1(int f) {
this.field1 = f;
}
public void setField2(int f) {
this.field2 = f;
}
public int getField2() {
return this.field2;
}
}
public class Tryouts {
public static void main(String[] args) {
int i = 0;
ArrayList<MyClass> list = new ArrayList<MyClass>();
while(i < 3) {
MyClass obj = new MyClass();
obj.setField1(40 + i);
obj.setField2(80+ i);
list.add(obj);
i++;
}
for (MyClass c : list) {
System.out.println(c.getField1() + "::" + c.getField2());
}
}
}
The output is
40::80, 41::81, 42::82

Categories