I have got started with Java Generics. in the below class, as the class is holding T, I want to have also a class which can extend T. Please help.
public class HolderUnique<T> {
private T a;
public HolderUnique(T a){
this.a = a;
}
public T getA() {
return a;
}
public void setA(T a) {
this.a = a;
}
}
Let's say you have a class S, which extends T, and you have also declared hold as a HolderUnique<T>. Let's also say you have declared sObj as type S. There is absolutely no reason why you cannot say T.setA(sObj).
Related
Suppose I have the following structure:
public interface A {
}
public interface B {
}
public interface B1 extends B {
}
public interface B2 extends B {
}
public class C implements A, B1 {
private final String s;
public C(final String s) {
this.s = s;
}
}
public class D implements A, B2 {
private final Exception e;
public D(final Exception e) {
this.e = e;
}
}
public class SomeClass<T> {
private final T t;
private final Exception e;
public SomeClass(final T t, final Exception e) {
this.t = t;
this.e = e;
}
public <U extends B> U transform(final java.util.function.Function<T, ? extends U> mapper1, final java.util.function.Function<Exception, ? extends U> mapper2) {
return t == null ? mapper2.apply(e) : mapper1.apply(t);
}
}
When now we do the following in another class:
public class AnotherClass {
public static void main(final String[] args) {
SomeClass<String> someClass = new SomeClass<>("Hello World!", null);
// this line is what is bothering me
A mappedResult = someClass.transform(C::new, D::new);
}
}
The code compiles without any problems. Why does the code compile? How is it possible that the type of 'mappedResult' can be A, even though the generic U in the method is declared to be a subtype of B?
Ok, so based on the comments on the question and some discussion with other people, there was a major point that I missed that might need addressing and that actually explains the answer given in the comments.
It's clear that the following compiles:
Object mappedResult = someClass.transform(C::new, D::new);
And yet Object is not a subclass of B, of course. The bound will ensure that the the types of C and D (in this case) will be a subtype of B, but they can be other types as well due thanks to other interfaces both C and D implement. The compiler will check what types they are and look at the most specific type(s) that they have in common. In this case, that is both A and B, so the type is derived to be A & B. Therefore, assigning this result to A is possible, because the compiler will derive the result to be an A as well.
The bound does provide some restrictions regarding the input, but not regarding the output and not regarding to the types of variables to which you can assign the result. That is what I was confused about before.
Another way to see this is the following: if the method had been defined as follows:
public <U> U transform(final java.util.function.Function<T, ? extends U> mapper1, final java.util.function.Function<Exception, ? extends U> mapper2) {
return t == null ? mapper2.apply(e) : mapper1.apply(t);
}
then the result can still be assigned to an A or a B when calling it as before. The bound had no influence on that. All it ensures here is that both mapper functions need to map to a result that is a subtype of U. With the bound, that becomes a subtype of U which is a subtype of B. But the fact that the result is a subtype of A doesn't change the fact that it is also a subtype of B. Therefore, the result can be assigned to either type.
class SingleTon{
Data<A> a;
Data<B> b;
Data<C> c;
// ... etc
class Data<O extends I<O>>{
O o;
public void update(O o){
this.o.update(o);
}
}
}
interface I<T>{
void update(T t);
}
class A implements I<A>{
private String a;
#Override
public void update(A a) {
this.a = a.a;
}
}
class B extends A implements I<B>{
private String b;
#Override
public void update(B b) {
super.update(b);
this.b = b.b;
}
}
class C implements I<C> {public void update(C c){}}
This code cannot be compiled, because super and sub-classes trying to implements the same interface but with different type arguments.
Interface I cannot be inherited with different type arguments (A,B), anyone has a workaround to solve this?
No workaround are possible with such a hierarchy : in B you want to implement the i interface with two distinct generic types : A and B.
Generics are designed to bring more type safety and this possible ambiguity defeats that. From the client of the class, why update(B b) would be valid but update(A a) would be not ?
So the compiler will never accept it.
But with composition you could do :
class B implements i<B>{
private A a;
private String b;
#Override
public void update(B b) {
super.update(b);
this.b = b.b;
}
}
And now you can use the A a field if needed from the B instance.
With the inheritance model given below, you'll achieve a contact of i through B in A. You don't really need to implement i for class B<T>.
See the example below:
interface i<T> {
}
class A<T> implements i<T> {
}
class B<T> extends A<T> {
}
Hope it helps you to understand the structure!
I do not understand what is needed, but this code is compiled))
interface i<T extends i<T>> {
void update(T t);
}
class A<Q extends A<Q>> implements i<Q> {
private String a;
#Override
public void update(A a) {
this.a = a.a;
}
}
class B<X extends B<X>> extends A<X> implements i<X> {
String b;
#Override
public void update(X b) {
super.update(b);
this.b = b.b;
}
}
I have a base class with a method called execute :
class A {
public execute(int a){}
}
I also have a class B, which extends A, but the execute method needs more parameters:
Currently, my solution is using optional parameters :
class B extends A {
public execute(int a, Object... parameters){
long b = (long)parameters[0];
boolean c = (boolean)parameters[1];
....
}
}
This would still be ugly because I must cast on parameters. Are there other options for this situation?
you can add an execute(int a, int b) in B, but it won't override the execute(int a) method, it will overload it. Both method will be callable on an instance of B.
This would break the OO paradigm. The L in solid stands for Liskov substitution principle.
The principle applied for you example is that B should behave as A.
A better solution would be to injects those parameters via the constructor and have an execute without any parameters.
class A {
int a;
public A(int a){
this.a = a;
}
public execute(){ // do something with a}
}
class B {
int a;
long b;
boolean c;
public B (int a, long b, boolean c) {
this.a = a;
this.b = b;
this.c = c;
}
public execute(){ // do something with a, b and c}
}
Here's an example from my code:
Baseclass:
abstract class AbstractBase implements Comparable<AbstractBase> {
private int a;
private int b;
public int compareTo(AbstractBase other) {
// compare using a and b
}
}
Implementation:
class Impl extends AbstractBase {
private int c;
public int compareTo(Impl other) {
// compare using a, b and c with c having higher impact than b in AbstractBase
}
FindBugs reports this as an issue. But why is that? What could happen?
And how would I correctly implement a solution?
Impl#compareTo(Impl) is not overriding AbstractBase#compareTo(AbstractBase) since they don't have the same signature. In other words, it won't be called when using Collections#sort for example.
EDIT: Added solution without casting
If you don't want to cast you could try the following.
Alter your baseclass to:
abstract class AbstractBase<T extends AbstractBase<?>> implements Comparable<T> {
//...
public int compareTo(T other) {
//...
}
}
And you Impl class to:
class Impl extends AbstractBase<Impl> {
//...
#Override
public int compareTo(Impl other) {
//...
}
}
Solution with casting:
A possible solution would be to override the compareTo(AbstractBase) method in the Impl class and explicitly check if an instance of Impl is passed in:
class Impl extends AbstractBase {
//...
#Override
public int compareTo(AbstractBase other) {
if (other instanceof Impl) {
int compC = Integer.compare(c, ((Impl) other).c);
if (compC == 0) {
return super.compareTo(other);
}
return compC;
}
return super.compareTo(other);
}
}
The following is something that I tried. Not exactly sure this is the reason why findbugs gives the error.
See the following code with a hypothetical implementation of the compareTo method.
Comparing the same objects results in different outputs.
public class Main
{
public static void main(String[] args)
{
Impl implAssignedToImpl = new Impl(1, 2, 3);
Impl otherImpl = new Impl(3, 2, 1);
System.out.println(implAssignedToImpl.compareTo(otherImpl)); // prints -2
AbstractBase implAssignedToAbstract = implAssignedToImpl;
System.out.println(implAssignedToAbstract.compareTo(otherImpl)); //prints 0
}
}
class AbstractBase implements Comparable<AbstractBase>
{
private int a;
private int b;
public AbstractBase(int a, int b)
{
super();
this.a = a;
this.b = b;
}
public int compareTo(AbstractBase other)
{
return (a + b) - (other.a + other.b);
}
}
class Impl extends AbstractBase
{
private int c;
public Impl(int a, int b, int c)
{
super(a, b);
this.c = c;
}
public int compareTo(Impl other)
{
return super.compareTo(other) + (c - other.c);
}
}
Building on my hypothetical compareTo, following seems to be a good solution. You can try to have a method similar to getSum which gives the object instance a value.
public class Main
{
public static void main(String[] args)
{
Impl implAssignedToImpl = new Impl(1, 2, 3);
Impl otherImpl = new Impl(3, 2, 1);
System.out.println(implAssignedToImpl.compareTo(otherImpl)); // prints 0
AbstractBase implAssignedToAbstract = implAssignedToImpl;
System.out.println(implAssignedToAbstract.compareTo(otherImpl)); //prints 0
}
}
class AbstractBase implements Comparable<AbstractBase>
{
private int a;
private int b;
public AbstractBase(int a, int b)
{
super();
this.a = a;
this.b = b;
}
public int compareTo(AbstractBase other)
{
return getSum() - other.getSum();
}
public int getSum()
{
return a + b;
}
}
class Impl extends AbstractBase
{
private int c;
public Impl(int a, int b, int c)
{
super(a, b);
this.c = c;
}
#Override
public int getSum()
{
return super.getSum() + c;
}
}
As sp00m said, your Impl#compareTo(Impl) has a different signature than AbstractBase#compareTo(AbstractBase), so it's not overloading it.
The key point is in understanding why it doesn't work, even when you try to sort() comparing with another Impl, where the more specific signature do matches.
As you defined Comparable<AbstractBase>, you need to define how your
instances compareTo AbstractBase instances. And so you need to implement compareTo(AbstractBase).
You can think that, being Impl a subtype of AbstractBase, the more specific method would be used when a comparison between two Impls takes place. The problem is Java has static binding, and so the compiler defines at compile time which method would use for solving each method call. If what you were doing was sorting AbstractBases, then the compiler would use the compareTo(AbstractBase), that is the one AbstractBase's interface define when it implements the Comparable(AbstractBase) interface.
You can make Impl implement the Comparable<Impl> interface for using the compareTo(Impl) method, but that would only work if you explicitly sort things that are known to be Impls at compile time (ie, an Impl object or Collection<Impl>).
If you really want to apply a different comparison whenever your two objects are Impls, you should fall to some kind of double-dispatch in your Impl#compareTo(AbstractBase) like:
Impl >>>
int compareTo(AbstractBase other) {
return other.compareToImpl(this);
}
int compareToImpl(Impl other) {
// perform custom comparison between Impl's
}
AbstractBase >>>
int compareTo(AbstractBase other) {
// generic comparison
}
int compareToImpl(Impl other) {
// comparison between an AbstractBase and an Impl.
//Probably could just "return this.compareTo(other);", but check for loops :)
}
This requires you add some Impl information in your AbstractBase, which is not pretty, though, but solves the problem the more elegant way it could - using reflection for this is not elegant at all.
The Liskov substitution principle (http://en.wikipedia.org/wiki/Liskov_substitution_principle) states: if S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e., objects of type S may substitute objects of type T) without altering any of the desirable properties of that program (correctness, task performed, etc.)
In your case, you are overriding the compareTo method from the Base class in a way that breaks the behaviour of the original method. This is probably why FindBugs has an issue with it.
If you want to be proper about it:
abstract class AbstractBase {
}
class Impl1 extends AbstractBase implements Comparable<Impl1> ...
class Impl2 extends AbstractBase implements Comparable<Impl2> ...
OR
even better, do not use the Comparable interface at all - use a Comparator at sort time instead.
However, in real life there are situations where you need to get around it (maybe you don't have access to the source of AbstractBase, or maybe your new class is just a POC). In these special cases, I would go with the "ugly" cast solution proposed by John.
In the following:
public interface SomeInteface<A, B> {
public B doSomething(A a);
}
I want to implement a version where the method doSomething returns the parameter a back.
I tried a Holder class;
class Holder<A> {
public A value;
public(A a){this.value = a;}
}
and return Holder. However, I am not sure how to define an implementation class of SomeInterface so that I am able to do this.
The following does not even compile:
public class SomeImplementation<X> implements SomeInterface<T> {
private class Holder<A> {
public A value;
public class Holder<A>{
public A value;
public(A a){this.value = a;}
}
}
class Implementation<A, Holder<A>> implements SomeInterface<A, Holder<A>>{
public Holder<A> doSomething(A a){
//do stuff
return new Holder(a);
}
}
}
What am I messing up here?
It needs to be
class Implementation<A> implements SomeInteface<A, Holder<A>>{
public Holder<A> doSomething(A a){
//do stuff
return new Holder<A>(a);
}
}
In the classname you define the generic variables and their constraints. You don't need a Holder variable.
I don't understand why you make it so difficult. You say
I want to implement a version where the method doSomething returns the
parameter a back.
Well, you can do just that:
public class SomeImplementation<A> implements SomeInterface<A, A> {
public A doSomething(A a) {
// do stuff
return a;
}
}
No need for a Holder class.
The interface SomeInterface does not put any constraints on the type parameters, so there's no reason why they can't be the same.
Alternatively, you can allow your implementation to be parameterized with two different types A and B where A extends B (could be useful in some cases):
public class SomeImplementation<A extends B, B> implements SomeInterface<A, B> {
public B doSomething(A a) {
// do stuff
return a;
}
}