Consider this example:
I have 3 interfaces: A, B, C, with methods a(), b(), c(); extending a base interface Intf;
I have a enum with options MyEnum.A, MyEnum.B, MyEnum.C;
I have a class extending this 3 interfaces: X implements A, B, C;
There is a way to implement a method in X like this;
public <T extends Intf> T getType (MyEnum enum)
and the result is the interface A, B or C, that is, accessing only method a(), b() or c()?
EDIT: I want to use it on a builder with fluent api:
X var = X.getType(MyEnum.A).a("value").build();
or
X var = X.getType(MyEnum.B).b("value").build();
but never
X var = X.getType(MyEnum.A).b("value").build(); //ERROR
You could dispatch the enum value, and return a matching instance, as #GhostCat suggested.
You could also invert the lookup, so each enum value provides an appropriate instance of Intf:
Variant 1: singleton instance per enum value
public enum MyEnum {
A(new AImpl()),
B(new BImpl()),
C(new CImpl());
private Intf instance;
MyEnum2(Intf instance) {
this.instance = instance;
}
public <T extends Intf> T getType() {
return (T) instance;
}
}
Variant 2: factory, creating new instances:
public enum MyEnum {
A(AImpl.class),
B(BImpl.class),
C(CImpl.class);
private Class<? extends Intf> type;
MyEnum(Class<? extends Intf> type) {
this.type = type;
}
public <T extends Intf> T getType() {
try {
return (T) type.newInstance();
} catch (InstantiationException | IllegalAccessException ex) {
throw new RuntimeException(ex.getMessage(), ex);
}
}
}
Usage:
A a = MyEnum.A.getType();
B b = MyEnum.B.getType();
C c = MyEnum.C.getType();
If I read your question correctly you want compile-time safety for
public <T extends Intf> T getType (MyEnum enum)
to return A for MyEnum.A, B for MyEnum.B etc.
You can achieve this compile-time safety if you make MyEnum class generic. This does now work with normal enums, but it works with old-fashioned "typesafe enum" pattern.
Assume we have three interfaces AA, BB , CC extending the base interface II:
public interface AA extends II { void a(); }
public interface BB extends II { void b(); }
public interface CC extends II { void c(); }
Now the class TT implements all of these interfaces:
public class TT implements AA, BB, CC {
#Override
public void a() { ... }
#Override
public void b() { ... }
#Override
public void c() { ... }
}
Now let EE be our generic pseudo-enum class, parameterized with some subtype of II:
public class EE<XX extends II> {
public static final EE<AA> A = new EE<AA>();
public static final EE<BB> B = new EE<BB>();
public static final EE<CC> C = new EE<CC>();
}
With these definitions the getType method can be declared as follows:
public <XX extends II> XX getType(EE<XX> enumVal)
This method may only return the type the type which parameterized the enumVal. Meaning
AA type = tt.getType(EE.A);
is valid but
BB type = tt.getType(EE.A);
is not.
One of the ways to implement the getType method would be delegate "conversion" of the TT instance to AA, BB or CC to the corresponding pseudo-enums:
public abstract class EE<XX extends II> {
public static final EE<AA> A = new EE<AA>() {
#Override
public <PP extends AA & BB & CC> AA convert(PP instance) {
return new AA() {
public void a() {
instance.a();
};
};
}
};
public static final EE<BB> B = new EE<BB>() {
#Override
public <PP extends AA & BB & CC> BB convert(PP instance) {
return new BB() {
public void b() {
instance.b();
};
};
}
};
public static final EE<CC> C = new EE<CC>() {
#Override
public <PP extends AA & BB & CC> CC convert(PP instance) {
return new CC() {
public void c() {
instance.c();
};
};
}
};
public abstract <PP extends AA & BB & CC> XX convert(PP instance);
}
You can also return instance directly, without wrapping in an anonymous inner class. But then the result can be force-casted to the other interfaces thus allowing access to other methods.
Finally, the implementation of getType is trivial:
public <XX extends II> XX getType(EE<XX> enumVal) {
return enumVal.convert(this);
}
From what I can see, the compiler won't allow
BB bb = tt.getType(EE.A);
Also
BB bb = (BB) tt.getType(EE.A);
bb.b();
won't work as in "produces ClassCastException in the runtime".
The disadvantages are a pseudo-enum construct and somewhat ugly implementation of convert.
Assuming that we are within class X, you have a local generic parameter, you could think of:
public <T extends Intf> T getType (MyEnum enumVal) {
if (enumVal == MyEnum.A) {
return (A) this;
if (enumVal == MyEnum.B) {
return (B) this;
But you don't gain anything from doing so. Those casts don't matter for the caller side.
Because there is nothing that the compiler could do for you here. You could write
A someA = whatever.getType(someEnum);
But you could as well write
B someB = whatever.getType(someEnum);
with the very same someEnum. And the compiler would be all happy.
If you want to achieve a gain on "compile time safety", you would have to somehow "connect" the argument type to the result type.
Related
I have two classes A and B and they both have a common field in them, and I want to create a function in which if I pass Class A object then I want to set that common field value to the passed value and if I pass Class B object then I want to set that common field value to the passed value. Can anyone please tell me how can I do this, I am new to Java Generic Classes.
Otherwise I would have to make two different functions OR I would have to make an if and else which would decide that passed object belongs to which class ??
Class A
public class A{
int footer;
public void setFooter(int fo) {
footer = fo;
}
}
Class B
public class B{
int footer;
public void setFooter(int fo) {
footer = fo;
}
}
Class D
public class D{
public void change_footer(T generic_param, int value) {
generic_param.setFooter(value);
}
}
Class HelloWorld
public class HelloWorld{
public static void main(String []args){
Here I want to call
A a = new A();
new D().change_footer(a, 5);
B b = new B();
new D().change_footer(b, 5)
}
}
Thank You
And if I got all of the question wrong, and nor A nor B are generic, AND the type of field is fixed.
then you mean something like:
class D {
/*public <T extends Super> would be muuuch nicer here as well!*/
public /*static*/ <T> void change_footer(T obj, int data) {
//otherwise, you could just cast to Super...and set dat field.
if (obj instanceof A) {
((A) obj).setField(data);
} else if (obj instanceof B) {
((B) obj).setField(data);
} // else ... ?
}
}
Original answer:
Easy peasy (the "straight forward" implementation produces the desired results.):
class A<T> {
T daField;
public void setField(T pField) {
daField = pField;
}
public T getField() {
return daField;
}
}
class B<T> extends A {//empty
}
class Test {
public static void main(String... args) {
B<Object> testB1 = new B<>(); //
testB1.setField(new Object());
System.out.println(testB1.getField());
B<String> testB2 = new B<>();
testB2.setField("blah blah");
System.out.println(testB2.getField());
B<Integer> testB3 = new B<>();
testB3.setField(42);
System.out.println(testB3.getField());
}
}
System.out:
java.lang.Object#6d06d69c
blah blah
42
It get's (little) more complicated, when you want to instantiate Ts ...but still possible/other question. :)
Edit to your comment:
If there's only one common field, then why not:
/*abstract */class Super<T> {
T daField;
public void setField(T pField) {
daField = pField;
}
public T getField() {
return daField;
}
}
? ...and:
class A<T> extends Super { ... }
class B<T> extends Super { ... }
I want to implement Builder Pattern with inheritance. So I have 4 following classes: one abstract class (ClassA), ClassB, ClassC. TestTest class is used to see how all this works:
public abstract class ClassA {
private String aString;
public String getaString() {
return aString;
}
public abstract class ClassABuilder<T extends ClassABuilder>{
public T setaString(String str) {
ClassA.this.aString = str;
return (T)this;
}
public abstract ClassA build();
}
}
public class ClassB extends ClassA{
private String bString;
public String getbString() {
return bString;
}
public class ClassBBuilder<T extends ClassBBuilder> extends ClassA.ClassABuilder<T>{
public T setbString(String str) {
ClassB.this.bString = str;
return (T)this;
}
#Override
public ClassB build(){
return ClassB.this;
}
}
}
public class ClassC extends ClassB{
private String cString;
public String getcString() {
return cString;
}
public static ClassCBuilder<ClassCBuilder> newBuilder(){
return new ClassC().new ClassCBuilder();
}
public class ClassCBuilder<T extends ClassCBuilder> extends ClassB.ClassBBuilder<T>{
public T setcString(String str) {
ClassC.this.cString = str;
return (T)this;
}
#Override
public ClassC build(){
return ClassC.this;
}
}
}
public class TestTest {
public static void main(String[] args) {
// TODO code application logic here
ClassC C=ClassC.newBuilder()
.setaString(null)
.setbString(null)
.setcString(null) //LINE XXX
.build();
}
}
The problem is that at TestTest at LINE XXX I get can't find symbol "setcString". What do I do wrong?
Let's track it down along the hierarchy:
First consider this signature:
class ClassABuilder<T extends ClassABuilder>
When you call setaString(null) the returned T will be an object that extends ClassABuilder. The compiler knows that this is a ClassBBuilder and thus will allow you to call setbString(null).
However, since the definition states T is required to extend a raw ClassBBuilder only any information on ClassBBuilder's generic types will be lost. Thus the compiler only knows that T is a ClassBBuilder but not that it's actually a ClassCBuilder which extends ClassBBuilder<ClassCBuilder> and hence doesn't know about setcString() on the returned type.
As has already been mentioned, using T extends ClassABuilder<T> will fix that since now the compiler knows there's another generic type to be passed down the hierarchy.
newBuilder() would then have to look like this:
public static ClassCBuilder<?> newBuilder(){
//you have too create a raw type here so you'll have to ignore/suppress/live with the warning
return (new ClassC().new ClassCBuilder());
}
As #AndyTurner already observed, the problem is that you use raw versions of your builder class types as type parameters. He did not go into detail, but the upshot is this:
ClassC C=ClassC.newBuilder() // yields a ClassCBuilder<ClassCBuilder>
.setaString(null) // yields a raw ClassCBuilder (type parameter)
.setbString(null) // yields a raw ClassBBuilder (type parameter bound)
.setcString(null) // ERROR: no such method on ClassBBuilder
.build();
To fix this with minimal change to your class structure and strategy, you must not only correct the type parameter bounds for your builder classes, as Andy advised ...
ClassABuilder<T extends ClassABuilder<T>>
... etc., but also make a change to ClassC.newBuilder(), such as to make it generic:
public static <T extends ClassCBuilder<T>> ClassCBuilder<T> newBuilder() {
return new ClassC().new ClassCBuilder<T>();
}
With that combination of changes, your code compiles for me.
I would like to post here the test demonstrating builder pattern with deep inheritance.
class TypeParamTest {
#Test
void test() {
Dd dd = Dd.builder()
.setIntAa(0)
.setIntBb(1)
.setIntCc(2)
.setIntDd(3)
.build();
assertEquals(0, dd.intAa);
assertEquals(1, dd.intBb);
assertEquals(2, dd.intCc);
assertEquals(3, dd.intDd);
}
abstract static class Aa {
int intAa;
static class AaBuilder<B extends AaBuilder> {
int intAa;
Aa build(Aa aa) {
aa.intAa = intAa;
return aa;
}
B setIntAa(int i) {
this.intAa = i;
return (B) this;
}
}
}
abstract static class Bb extends Aa {
int intBb;
static class BbBuilder<B extends BbBuilder<B>>
extends AaBuilder<B>
{
int intBb;
Bb build(Bb bb) {
bb = (Bb) super.build(bb);
bb.intBb = intBb;
return bb;
}
B setIntBb(int i) {
this.intBb = i;
return (B) this;
}
}
}
static class Cc extends Bb {
int intCc;
static CcBuilder<?> builder() {
return new CcBuilder<>();
}
static class CcBuilder<B extends CcBuilder<B>>
extends BbBuilder<B>
{
int intCc;
Cc build() {
return build(new Cc());
}
Cc build(Cc cc) {
cc = (Cc) super.build(cc);
cc.intCc = intCc;
return cc;
}
B setIntCc(int i) {
this.intCc = i;
return (B) this;
}
}
}
static class Dd extends Cc {
int intDd;
static DdBuilder<?> builder() {
return new DdBuilder<>();
}
static class DdBuilder<B extends DdBuilder<B>>
extends CcBuilder<B>
{
int intDd;
Dd build() {
return build(new Dd());
}
Dd build(Dd dd) {
dd = (Dd) super.build(dd);
dd.intDd = intDd;
return dd;
}
B setIntDd(int i) {
this.intDd = i;
return (B) this;
}
}
}
}
I have the sama java object TestData in to packages (A & B). I have made a function that processes the object for a standard business functionality.
CommonFunc.java:
import A.TestData ;
class CommonFunc
{
/// .....
public static TestData processTestData(Date d1, String s1){
TestData testData = new TestData ();
/// set some testData porperties based on d1 and s1
/// e.g : testData.setInitialDate(d1);
return testData ;
}
}
The problem here is that the compiler has to load the object from one of the packages lets say package (A), so when I expect the data to be returned to a local variable from package (B) I get incompatible type error :
File using B TestData and needs to call the function processTestData:
import B.TestData;
// ...
TestData obj = CommonFunc.processTestData(new Date(), "test");
// ...
Is there a way to overcome this problem keeping a common function for both?
Is there a way to overcome this problem keeping a common function for both?
No and yes. On the general case, you cannot.
But you can, IFF you can make the two classes adopt the same interface, with the common methods declared in the same interface. See below, with apologies for the change in the class names:
interface C {
public Date getA();
public void setA(Date a);
}
interface C_Factory <X extends C> {
X createInstance();
}
class C1 implements C {
Date a;
int b;
public C1() {
super();
}
public Date getA() { return a; }
public void setA(Date a) { this.a = a; }
public int getB() { return b; }
public void setB(int b) { this.b = b; }
}
class C2 implements C {
Date a;
float b;
public C2() {
super();
}
public Date getA() { return a; }
public void setA(Date a) { this.a = a; }
public float getB() { return b; }
public void setB(float b) { this.b = b; }
}
public class CommonFunc {
// You need this extra param to create instances----
// V
static <X extends C> X doSomething(Date d, Class<X> clazz)
throws InstantiationException, IllegalAccessException
// You'll have to accept those exceptions as well
{
// the next statement uses clazz as a factory for new X instances
// As such, you can abstract the method further and use
// a custom Factory class instead.
X toret=clazz.newInstance();
toret.setA(d);
// something else
return toret;
}
// A custom factory variant of the above
static <X extends C> X doSomething(Date d, C_Factory<X> factory)
{
X toret=factory.createInstance();
toret.setA(d);
// something else
return toret;
}
static public void main(String[] args) {
try {
C1 c1=doSomething(new Date(), C1.class);
C2 c2=doSomething(new Date(), C2.class);
} catch (InstantiationException | IllegalAccessException e) {
// Should not happen
e.printStackTrace();
}
}
}
I do not see how it is possible in the above example you have posted, The best way out is to make the TestData an interface and have implementations in 2 packages. Then, to decide whether to return A TestDataImpl or B TestDataImpl, take another parameter in the processData, for simplicity, let us say a boolean. Based on true or false instantiate A TestDataImpl or B TestDataImpl and return the same. Where the return type of processData is the interface type
This is probably would be the most straightforward way of reusing the processData method.
I want to have a method in an interface that returns a class whose type is not defined in the package. The implementing class will then return a specific type. I can see at least 3 methods how I can do this, shown below as fn1, fn2 and fn3. In all cases there is some form of unchecked cast. Is any of these methods preferred? or is there something better? (assume that the interface I1 and the method dostuff are in some other jar package and do not have access to the Test or the Integer class)
public class Myclass {
public interface I1
{
Object fn1();
<T> T fn2();
<T> T fn3();
}
public class Test implements I1
{
#Override
public Integer fn1() {
return new Integer(1);
}
#Override
public <T> T fn2() {
return (T) new Integer(2); //requires cast to T
}
#Override
public Integer fn3() { //automatic unchecked conversion to T in return value
return new Integer(3);
}
}
public static void main(String[] args) {
Myclass c = new Myclass();
I1 t = c.new Test();
Integer i = (Integer) t.fn1(); //cast required here since I1.fn1() returns Object
Integer j = t.fn2();
Integer k = t.fn3();
dostuff(t);
}
static void dostuff(I1 p)
{
Object i = p.fn1();
Object j = p.fn2();
Object k = p.fn3();
}
}
Can't you use generics with the Interface? Like
public interface I1<T> {
T fn1();
// etc
}
Then there's no casting required when you refer to T.
That's what I prefer, at least. You can then also of course specify what you want T to be using
<T extends myInterface>
I would do it this way
public interface I1<T> {
T fn1();
}
public class Test implements I1<Integer> {
#Override
public Integer fn1() {
return new Integer(1);
}
}
public static void main(String[] args) {
Myclass c = new Myclass();
I1<Integer> t = c.new Test();
Integer i = t.fn1(); <-- no cast
}
Suppose I have a class A and a class B.
public class A {
private B b;
public A() {
this.b = new B();
}
public B getB() {
return this.b;
}
}
public class B {
public String getSome() {
return "Get some!";
}
}
I know I can get B through A, because A has (or owns) B: new A().getB().
But if I have B, can I get A?
Sure, just add routine getA() in you class B, and change the line in your constructor to
public A() {
this.b = new B(this);
}
This of course assumes your class B has a constructor which accepts an A, e.g.,
public B(A a) {
this.a = a;
}
B needs an explicit reference to its owner:
public class B {
private final A owner;
public B(A owner) {
this.owner = owner;
}
public A getOwner() {
return owner;
}
}
And in A:
public A() {
b = new B(this);
}
Nope. There is no such thing as an 'owner' in Java. Any object can be referenced by any number of other objects.
If you need B to always be bound to an instance of A, make B an inner class of A:
class A {
B b = new B();
class B {
String getSome() {
// this will refer to the enclosing A
return A.this.toString();
}
}
}
An inner (non-static) class always has an implicit reference to the enclosing instance and cannot exist without it. In order to instantiate B from outside, you need a nasty syntax: B b = new A().new B();
No you cannot. B has no reference to A.
No.
Class a has reference to class B, but class B has no reference to class A. References are one way only.
No, that's not possible. You're looking for backreferences, but we have to create them in the code if needed.
If you want to collect all referencers to B, you could do this with a constructor or with a factory (pattern) that creates B's. I'll show the factory:
public class B {
private static Set<? extends Object> referencers = new HashSet<? extends Object>();
private B(){} // no public constructor
public static create(Object parent) {
// cooperative approach, the caller should pass "this"
referencers.add(parent);
}
public static remove(Object parent) {
referencers.remove(parent);
}
}
you can also use inner classes
package test;
public class A {
B b = null;
public B getB()
{
return b;
}
public class B {
public A getA()
{
return A.this;
}
}
public static void main(String[] args) {
B b = new A().new B();
}
}