Java - Generic, Factory Class - java

Here is a Java code structure:
public interface MyBaby<T> {...}
public class A implements MyBaby<Foo> {...}
public class B implements MyBaby<Boo> {...}
public Class Foo {...}
public Class Boo {...}
public class MyFactory {
...
public synchronized static MyFactory getInstance() {...}
public MyBaby<?> getMyBaby(BabyType type) {...}
}
The above code structure is working with a little problem. To have an instance, I need to do a down casting such as
MyBaby<Foo> baby = (MyBaby<Foo>) MyBabyFactory.getInstance().getMyBaby(BabyType.CUTE);
How to change the code so that the down casting isn't needed?

You should pass a Class object like this.
public <T> MyBaby<T> getMyBaby(Class<T> type) {
return (MyBaby<T>) (type == Foo.class ? new A() : new B());
}
And
MyBaby<Foo> a = MyFactory.getInstance().getMyBaby(Foo.class); // OK
MyBaby<Foo> b = MyFactory.getInstance().getMyBaby(Boo.class); // Compile error

Related

Basic Java interface return object in a class that implements the interface

public interface foo {
String ex(String a);
}
public class myclass implements foo {
public String ex(String a) {
//define the method
return a;
}
public static foo getsome() {
//have to return for example if I do ex("abc") return "123" but have to retrun the object of the interface o.O
}
}
I don't know how to return an object of an Interface because I know that an object of interface cannot be implemented. On the other side, get methods of the all commands has no input. So what can I do?
I will call object, an instance of a class, for example:
private myclass myObject = new myclass();
This object (myObject) can be accesses as its class (myclass), any interface it implements (foo) or any class it extends (Object, because every class extends Object in Java). So the following are all valid:
public myclass getMyClass() { return myObject; }
public foo getMyFoo() { return myObject; }
public Object getMyObject() { return myObject; }
So coming back to your code, if you want to use a static method:
private static myclass instance = new myclass();
public static foo getsome() {
return instance;
}

Confusion with generics, java

I have generic class :
public class Test<T> {
private Test<? extends T> myInstance;
public Test<? extends T> getInstance () {
return myInstance;
}
public void setInstance (Test<? extends T> argType) {
this.myInstance = argType;
}
}
And I have two classes in my class hierarchy relations:
public abstract class Alphabet {
//code here
}
and
public class A extends Alphabet{
public A() {
super();
System.out.print("This is A call");
}
}
Finally I have a class where I want to store make generic class Test with particular type and set new Instance of Object -> A through setInstance() method:
public static void main(String[] args) {
List<Alphabet> list = new ArrayList<Alphabet>();
Test<Alphabet> tAlphabet = new Test<Alphabet>();
tAlphabet.setInstance(new A()); //Here is compilation ERROR
}
But I have got the compilation error in line tAlphabet.setInstance(new A());
What is the issue with my generic class?
Your instance is a Test object as it's currently written, and you are supplying it with an Alphabet object instead. You probably want your instance to be of type Alphabet:
public class Test<T> {
private T myInstance;
public T getInstance() {
return myInstance;
}
public void setInstance(T argType) {
myInstance = argType;
}
}
This way, your Test stores an Alphabet instead of another Test.
It seems you have made things more complicated than needed. You probably want this in your Test class instead of what you actually have:
private T myInstance;
public T getInstance () {
return myInstance;
}
public void setInstance (T argType) {
this.myInstance = argType;
}
With this arrangement you would be free to setInstance(new A()) on a Test<Alphabet> instance.

Declare an object that implements an interface without explicitly using a specific class

Assume I have
public interface MyInterface {
public void aMethod();
}
public class MyClass implements MyInterface {
#Override
public void aMethod() {
Log.d("aMethod");
}
}
And I want to declare an object that implements MyInterface, so I can instantiate it in the constructor as follows
public class AnotherClass {
Class <? extends MyInterface> mObjectThatImplements;
public AnotherClass() {
// Says it cannot convert MyClass to Class <? extends MyInterface>
mObjectThatImplements = new MyClass();
}
}
You just change the declaration type. Make it as a Interface, and you can assign any implementation to it.
public class AnotherClass {
MyInterface mObjectThatImplements;
public AnotherClass() {
mObjectThatImplements = new MyClass();
}
}

overriding interface method

For a interface such as
public interface something<T>
{
public something<T> somemethod();
}
from what i understand the abstract method somemethod() needs to overridden with a method that returns an object implementing the interface. However, any attempts to do so have given me the "does not override the abstract method somemethod()" compiler error.
I've tried doing something like
public class someclass {
...
public something<T> somemethod() { ... return new someclass(); }
...
or
public someclass somemethod() { ... return new someclass(); }
...
}
How exactly would i implement such a method?
You're missing the generic declaration in your implementing class. Here's an example:
public interface Something <T> {
public Something<T> someMethod();
}
class SomethingImplementation <T> implements Something <T> {
#Override
public Something<T> someMethod() {
return null;
}
}
All of these should compile:
class test<T> implements something<T>{
public something<T> somemethod(){
return new test<T>();
}
}
class test1<T> implements something<T>{
public test1<T> somemethod(){
return new test1<T>();
}
}
class test2 implements something<Integer>{
public something<Integer> somemethod(){
return new test2();
}
}
class test3 implements something<Integer>{
public test3 somemethod(){
return new test3();
}
}
First of all, your someclass does not implement the interface in your code example above. You can make it implement the interface for a specific, concrete type, as in the following example, where String is used as the concrete type. The method then would need to return a something<String>.
public class someclass implements something<String> {
public something<String> somemethod() {
return new someclass();
}
}
Or you could have class someclass have a type parameter and use that for the interface:
public class someclass<X> implements something<X> {
public something<X> somemethod() {
return new someclass<X>();
}
}
from what i understand the abstract method somemethod() needs to
overridden with a method that returns an object implementing the
interface.
That is not correct. The method somemethod needs to return a something<T>.
You also need to extend the interface with a generic, such as:
public class someclass implements something {
public something somemethod() {
...
}
}
To override a method you have to implement a method with the same types of paramenters and the same type of return value.
String something(){} will be overriden by String something(){}
but NOT with char[] something(){} or String something(int){}
As I understand, you need to implement interface something, You can do this in simple way:
public class someclass<T> implements something<T> {
public something<T> somemethod() { ... return new someclass(); }
}
public class someclass<T> extends something<T> {
public something<T> somemethod() { ... return new someclass<T>(); }}

Overriding Java generic methods

I wanted to create an interface for copying an object to a destination object of the same class. The simple way is to use casting:
import org.junit.Test;
import org.junit.internal.runners.JUnit4ClassRunner;
import org.junit.runner.RunWith;
#RunWith(JUnit4ClassRunner.class)
public class TestGenerics {
public static interface Copyable {
public void copy(Copyable c);
}
public static class A implements Copyable {
private String aField = "--A--";
protected void innerCopy(Copyable c) {
A a = (A)c;
System.out.println(a.aField);
}
public void copy(Copyable c) {
innerCopy(c);
}
}
public static class B extends A {
private String bField = "--B--";
protected void innerCopy(Copyable c) {
B b = (B)c;
super.innerCopy(b);
System.out.println(b.bField);
}
}
#Test
public void testCopy() {
Copyable b1 = new B();
Copyable b2 = new B();
b1.copy(b2);
}
}
But also i've found a way it can be done using generics:
import org.junit.Test;
import org.junit.internal.runners.JUnit4ClassRunner;
import org.junit.runner.RunWith;
#RunWith(JUnit4ClassRunner.class)
public class TestGenerics {
public static interface Copyable<T> {
public void copy(T t);
}
public static class A<T extends A<?>> implements Copyable<T> {
private String a = "--A--";
public void copy(T t) {
System.out.println(t.a);
}
}
public static class B<T extends B<?>> extends A<T> {
private String b = "--B--";
public void copy(T t) {
super.copy(t);
System.out.println(t.b);
}
}
#Test
#SuppressWarnings("unchecked")
public void testCopy() {
Copyable b1 = new B();
Copyable b2 = new B();
b1.copy(b2);
}
}
Though the only way i've found to get rid of warnings is the annotation. And it feels like something is wrong.
So what's wrong? I can accept that something is wrong in the root of the problem. So any sort of clarification is welcome.
Your interface definition:
public interface Copyable<T extends Copyable<T>> {
void copy(T copyFrom);
}
Your implementation:
public class Example implements Copyable<Example> {
private Object data;
void copy(Example copyFrom) {
data = copyFrom.data;
}
//nontrivial stuff
}
That should take care of your warnings.
Assuming you don't want to subclass further you just need:
public static /*final*/ class AClass implements Copyable<AClass> {
For an abstract class, you do the "enum" thing:
public static abstract class AClass<T extends AClass<T>> implements Copyable<T> {
In testCopy, one of the warnings is because you're instantiating a "raw type" of Copyable rather than some concrete Copyable<T>. Once you instantiate a Copyable, it can only be applied to Ts (which include subtypes of T). In order to instantiate with a formal type, the class definitions will need to be changed slightly:
public static class A<T extends A> implements Copyable<T>
public static class B<T extends B> extends A<T>
The next issue is that a Copyable<B> can only be passed a compile-time type of B (based on the definition of Copyable). And testCopy() above is passing it a compile-time type of Copyable. Below are some examples of what will work, with brief descriptions:
public void testExamples()
{
// implementation of A that applies to A and subtypes
Copyable<A> aCopier = new A<A>();
// implementation of B that applies to B and subtypes
Copyable<B> bCopier = new B<B>();
// implementation of A that applies to B and subtypes
Copyable<B> bCopier2 = new A<B>();
}
I keep trying to figure out a way to get rid of the warnings in your first approach and I can't come up with anything that works. Even so, I think the first approach is the lesser of two evils. An unsafe cast is better than needing to give your classes such a complicated api.
A completely separate approach would be to override Object.clone() and implement Cloneable.
This is the best possible code of second approach. It compiles without any warnings.
import static org.junit.Assert.fail;
import org.junit.Test;
import org.junit.internal.runners.JUnit4ClassRunner;
import org.junit.runner.RunWith;
#RunWith(JUnit4ClassRunner.class)
public class TestGenerics {
public static interface Copyable<T> {
public void copy(T t);
}
public static class A<T extends A<T>> implements Copyable<T> {
private String a = "--A--";
public void copy(T t) {
System.out.println(t.a);
}
#SuppressWarnings("unchecked")
public static Copyable<Object> getInstance() {
return new A();
}
}
public static class B<T extends B<T>> extends A<T> {
private String b = "--B--";
public void copy(T t) {
super.copy(t);
System.out.println(t.b);
}
#SuppressWarnings("unchecked")
public static Copyable<Object> getInstance() {
return new B();
}
}
#Test
public void testCopy() {
Copyable<Object> b1 = B.getInstance();
Copyable<Object> b2 = B.getInstance();
Copyable<Object> a = A.getInstance();
b1.copy(b2); // this works as intended
try {
b1.copy(a); // this throws ClassCastException
fail();
} catch (ClassCastException cce) {
}
}
}
And also i figured out all that happens in this program with help of reflection:
for (Method method : A.class.getMethods()) {
if (method.getName().equals("copy")) {
System.out.println(method.toString());
}
}
for (Method method : B.class.getMethods()) {
if (method.getName().equals("copy")) {
System.out.println(method.toString());
}
}
Here is the output:
public void com.sbp.core.TestGenerics$A.copy(com.sbp.core.TestGenerics$A)
public void com.sbp.core.TestGenerics$A.copy(java.lang.Object)
public void com.sbp.core.TestGenerics$B.copy(com.sbp.core.TestGenerics$B)
public void com.sbp.core.TestGenerics$B.copy(com.sbp.core.TestGenerics$A)
public void com.sbp.core.TestGenerics$A.copy(java.lang.Object)
It means that:
The copy(...) methods in A and B make compiler generate "bridges" -
2 different methods for each, one with reifed argument type from
ancestor (reified T from Copyable becomes Object, reified "T extends
A" from A becomes A) and that is why it's override and not overload,
and the other one with reified argument type for defining class. First
method (with autogenerated body) downcasts its argument to call the
second (they call it a bridge). Because of this downcasting we get
ClassCastException in runtime if we call b1.copy(a).
It looks like direct type casting is cleaner and better tool for my
problem and generics are better used in their direct purpose - to
enforce compile time type checking.
I've learned Scala and now i know that the thing i wanted 2 years ago could have been achieved with contravariant type parameter and Scala's type system:
trait CopyableTo[-T] {
def copyTo(t: T)
}
class A(private var a: Int) extends CopyableTo[A] {
override def copyTo(t: A) {
println("A:copy")
t.a = this.a
}
}
class B(private var a: Int, private var b: Int) extends A(a) with CopyableTo[B] {
def copyTo(t: B) {
println("B:copy")
super.copyTo(t)
t.b = this.b
}
}
#Test
def zzz {
val b1 = new B(1, 2)
val a1 = new A(3)
val b2 = new B(4, 5)
b1.copyTo(a1)
a1.copyTo(b1)
b1.copyTo(b2)
}
Java type system is too weak for this.

Categories