I have the below hierarchy of classes which just implement the imaginery functionality of encoding and decoding the animals from the given bytearrays.
public abstract class Animal {
}
class Tiger extends Animal{
private String name;
public void setName() {
}
public String getName() {
return this.name;
}
}
abstract class AnimalTransformer {
public static <T> T decodeAnimalFromBytes(byte[] animalInBytes) {
return null;
}
public static byte[] encodeAnimalInBytes(Animal animal) {
return null;
}
}
class TigerTransformer extends AnimalTransformer{
public static Tiger decodeAnimalFromBytes(byte[] animalInBytes) {
return new Tiger();
}
public static byte[] encodeAnimalinBytes(Tiger tiger) {
return new byte[0];
}
}
On overriding method from the AnimalTransformer abstract class in the TigerTransformer class which extends AnimalTransformer , i get the following warning
Type safety: The return type Tiger for decodeAnimalFromBytes(byte[]) from the type
TigerTransformer needs unchecked conversion to conform to T
from the type AnimalTransformer
I understand the cause of this warning but unfortunately i am not able to solve it as i am new to generics. Can someone briefly explain how can this warning be remedied?
Note that there's no use in making the methods of AnimalTransformer static. Static methods don't override each other by inheritance. Furthermore, you are not binding the data type the transformer works on to the type of the decoded object (e.g., TigerTransformer can return Horse objects).
I would do the following instead, which I consider to be more type safe:
abstract class AnimalTransformer <T> {
public abstract T decodeAnimalFromBytes(byte[] animalInBytes);
public abstract byte[] encodeAnimalInBytes(T animal);
}
First of all, don't try to 'override' with static methods. It does not work the way you think it does - the 'overridden' static methods can still be accessed from the subclass in devious (accidental) ways. If you want overriding behavior, use local methods.
The warning is being generated because the Tiger method signature is not compatible with what the super-class method promises - that any class <T> chosen by the client can be decoded to, which is a very big, unfulfillable promise.
A better method would be:
abstract class AnimalTransformer<T extends Animal> {
public T decodeAnimalFromBytes(byte[] animalInBytes) {
return null;
}
public static byte[] encodeAnimalInBytes(T animal) {
return null;
}
}
class TigerTransformer extends AnimalTransformer<Tiger> {
public Tiger decodeAnimalFromBytes(byte[] animalInBytes) {
return new Tiger();
}
public byte[] encodeAnimalinBytes(Tiger tiger) {
return new byte[0];
}
}
This represents what you are trying to model more clearly - an AnimalTransformer provides transformation methods for some subclass of Animal, and it is up to the subclass, or anonymous implementation, to clarify which.
Related
In this case my IDE shows compilation error in return statement.
public class Base<T extends Base>{
public T get(){
return this;
}
}
When I add a typecast as in code bellow everything works fine, however I don't get why typecast is needed.
public class Base<T extends Base>{
public T get(){
return (T) this;
}
}
Doesn't Java replace all bounded generic occurrences with bounded type? Can someone explain what is going on under the hood and why typecast is needed?
Edit 1.
Thanks to Lothars and algrid answers it is now clear that this standalone case can cause ClassCastException. This is not safe so Base should probably be abstract.
The intent of this is to create a base class for Builder classes so that extended methods would return the type of the extending class. This is needed for method chaining. In the example bellow the return type of child.setParamOne(1) will be Child despite the fact that it is defined above in the inheritance hierarchy.
Is this code safe? Do you have any suggestions or alternatives for approaching this problem?
public abstract class Base<T extends Base>{
int paramOne;
public T setParamOne(int param){
this.paramOne = param;
return (T) this;
}
}
public final class Child extends Base<Child> {
int paramTwo;
public Child setParamTwo(int param){
this.paramTwo = param;
return this;
}
}
public static void main(String[] args) {
Child c = new Child()
.setParamOne(1)
.setParamTwo(1);
}
Why do you think that your this is of the type T? It's of the type Base<T>.
Try to run the following code and you'll get ClassCastException:
public class Main {
public static void main(String[] args) {
Base<Child> b = new Base<>();
// b.get() returns an instance of Base, not Child (however it's mistakenly cast to Child)
Child1 c = b.get();
}
public static class Base<T extends Base>{
public T get(){
return (T) this;
}
}
public static class Child extends Base {
}
}
The reason for this error is the same as the error being created for code like this:
public void myMethod(InputStream is) {
ByteArrayInputStream bais = is;
}
Just with generics. To get rid of the complier error you can do the cast as you did in your code:
public void myMethod(InputStream is) {
ByteArrayInputStream bais = (ByteArrayInputStream) is;
}
But this will fail during runtime if the passed inputstream is not a ByteArrayInputStream or a class derived from it. The same will happen with your code. Unless you only create instances of Base<Base> the cast will lead to an error when calling get.
In your example:
public class Base<T extends Base>{
public T get(){
return this;
}
}
the return statement is incorrect, because this is an instance of Base<T> and not T.
If your aim is to return the instance itself (by the way, I'm not sure why you would be doing this), the code should look like this:
public class Base<T extends Base>{
public Base<T> get(){
return this;
}
}
If your aim is to return the parameterized type, then you will probably not be able to do that. The parameterized type itself is not an instance within the Base class, but, again, just the parameterized type. If that is what you need, you can get the parameterized type class using reflection.
The conversion is unsafe because this (which has type Base<T>) may not be a T. We only know that T is a Base, but not the other way around.
There is no way to represent a "self type" in Java. So what you want to do is impossible. Instead, you can make an abstract method that forces implementing subclasses to provide a way to return a T:
public class Base<T> {
public abstract T get();
}
public final class Child extends Base<Child> {
public Child get() {
return this;
}
}
This seems to be a compiler issue, or maybe this is there by design.
ClassA is a class with two generics. ClassB will extend ClassA by providing one solid generic type, but still expose another one.
In the following example, E will be passed in type that will extend ClassA, so when any method is called, then returned type will still be the subtype which enables to call the subtype method if needed. The motivation behinds this is to do a builder pattern, e.g.
ClassB b = new ClassB<String>().m1().m2().m3().m4()......
public class ClassA<E, T> {
public final E e;
public final T t;
public ClassA(T t) {
this.e = (E)this;
this.t = t;
}
public E printA() {
System.out.println("AAAAAA");
return e;
}
}
public class ClassB<T> extends ClassA<ClassB, T> {
public ClassB(T t) {
super(t);
}
public ClassB printB() {
System.out.println("BBBBBB");
return this;
}
public static void main(String[] args) {
ClassB<String> classB = new ClassB<>("Hello World");
// classB.printA().printA().printA(); // This will fail, after the second printA() return Object type instance instead of ClassB.
System.out.println(classB.printA().printA().getClass()); // This will print "class ClassB", so the class information it still there.
((ClassB)classB.printA().printA()).printA(); // Casting the instance to ClassB again will make it work again.
}
}
The problem is that when you call the method two times, the return instance type will be lost, so it will be an Object type, and cannot call any ClassA/B method without casting it. This is super weird.
Any idea?
Your class ClassB is a generic one, but you are opting out of generics when not providing a type parameter.
And you are doing exactly that here
public class ClassB<T> extends ClassA<ClassB, T>
^^^^^^
and here
public ClassB printB()
^^^^^^
So simply change these lines to
public class ClassB<T> extends ClassA<ClassB<T>, T>
^^^
and
public ClassB<T> printB()
^^^
Then it will work.
I am creating a function with a generic type and that generic type is an abstract type which I need to instantiate. This code will explain it more clearly:
public <T extends AbstractRow> foo(){//no I did not actually name the function foo
ArrayList<T> arr=new ArrayList<T>();
arr.add(new T(...)); //cant instantiate objects of abstract class
}
Basically I want to enforce "T extends AbstractRow but is not Abstract itself".
I realize you can't instantiate abstract classes, so I'd like a suggestion on a workaround or some other method that would allow me to mimic the behavior of creating an object of a generic type.
As far as I know, there's two ways to do this:
Add a Class<T> type field to your abstract generic class, and set it through the constructor (or another method). You can then invoke type.newInstance() to create the object.
Create a factory interface Factory<T> with a T create() method and set that as a field on your abstract class through the constructor (or another method). Upon creating a concrete instance of your generic class, you also have to pass a concrete implementation of said factory.
import java.util.ArrayList;
import java.util.List;
public class Generic<T> {
private Factory<T> factory;
public Generic(Factory<T> factory) {
this.factory = factory;
}
public void foo() {
List<T> list = new ArrayList<>();
list.add(factory.create());
}
}
interface Factory<T> {
T create();
}
Usage:
Generic<Bar> concrete = new Generic<>(new Factory<Bar>() {
#Override
public Bar create() {
return new Bar();
}
});
concrete.foo();
Your main issue isn't that you're working with an abstract class - in which case the suggestions posted in the comments would be useful. The bigger problem is that you're trying to instantiate a generic type directly (read: new T()) - which, simply put, you can't do in Java because of type erasure.
That said, there's always a workaround:
/**#param clazz the subclass you want to instantiate */
public <T extends AbstractRow> foo(Class<T> clazz) {
ArrayList<T> arr = new ArrayList<T>();
arr.add(clazz.newInstance); //instantiate new instance of given subclass
}
Usage:
abstract class Test1 {}
class Test2 extends Test1{ }
class Test<T> {
public static <T extends Test1> T foo(Class<T> clazz) {
T toReturn = null;
try{ toReturn = clazz.newInstance(); } catch (Exception e) { };
return toReturn ;
}
public static void main(String[] args) {
Test1 t1 = t.foo(test2.class);
System.out.println(t1.getClass()); //prints "class pkgname.test2"
}
}
The code below is a simplified version of the pattern my project is using. The standard pattern we use is to have a Writer for each object type. For the subtypes of one abstract type (in this example Animal), I'd like an enum to serve as a lookup for the correct writer.
abstract class Writer<T> {
abstract void write(T value);
}
abstract class Animal {
abstract AnimalType getType();
}
class Cat extends Animal {
AnimalType getType() { return AnimalType.CAT; }
}
class CatWriter extends Writer<Cat> {
void write(Cat value) { }
}
// The AnimalType stores a reference to the correct writer for the Animal subclass
enum AnimalType {
CAT(new CatWriter());
Writer<? extends Animal> writer;
Writer writerThatWorksWithWarning;
Writer<Animal> writerThatWorksButCantBeAssigned;
AnimalType(Writer<? extends Animal> writer) {
this.writerThatWorksWithWarning = writer;
this.writer = writer;
// ERROR: Incompatible Types
this.writerThatWorksButCantBeAssigned = writer;
}
}
Sample use case:
class Test {
public static void main(String... args) {
Animal value = new Cat();
// ERROR: write (capture<? extends Animal) in Writer cannot be applied to (Animal)
value.getType().writer.write(value);
// WARNING: Unchecked call
value.getType().writerThatWorksWithWarning.write(value);
// This line works fine here - but can't be assigned above
value.getType().writerThatWorksButCantBeAssigned.write(value);
}
}
I think that my problem is similar to the problem in this question: Java Generics with wildcard, however I can't tell how to solve it.
I've put the inline errors and warnings I get in the comments.
Any ideas?
I think the issue here is that you can't represent a type hierarchy with an enum, so there's no way to tell the type system that for enum { CAT, DOG; } the CAT should type to CAT extends Animal and the DOG types to DOG extends Animal. So But since you have a class hierarchy already, why not use that? i.e. something like :
public interface Writer<T> {
public void write(T t);
}
public abstract class Animal<T extends Animal<T>> {
public abstract Writer<T> getWriter()...
}
public class Cat extends Animal<Cat> {
#Override
public Writer<Cat> getWriter()...
}
It seems to me that what you're really using the enum for is something more like a hashmap of <Class, Writer<Class>>, sort of a built in singleton. You can do this, but only by hiding the types.
I would have animals unaware of writers. they are animals after all.
You can have a Map<Class,Writer>, and for each entry in it, you maintain that the key Class<X> and value Writer<X> are about the same type X. We can't express that relation in types, so casts must be done at some places. If looking up fails for a type (say Cat), try looking up again with its super types (Animal)
A type safe public API can be designed like
static public <T> void registerWriter(Class<T> type, Writer<T> writer)
static public <T> Writer<? super T> getWriter(Class<T> type)
Suppose we don't have a Writer directly mapped to Cat, but we do have a Writer<Animal> for Animal, then that writer will be returned for Cat.class. That is ok, because that writer does accept all animals.
This convenient method can be provided:
static public static void write(Object obj)
from the type of the object, a suitable writer can be found, and the writer will accept the object.
Try this instead,
enum AnimalType {
CAT(new CatWriter());
private Writer<? extends Animal> writer;
AnimalType(Writer<? extends Animal> writer) {
this.writer = writer;
}
public Writer<Animal> getWriter() {
return (Writer<Animal>)writer;
}
}
Moreover, I am not sure what are you up to. But I believe that Visitor pattern will come handy in this case.
Problem with the above solution, the code below will break the thing.
Animal cat = new Cat();
Animal dog = new Dog();
cat.getType().getWriter().write(cat);
// java.lang.ClassCastException in the write() method's argument
cat.getType().getWriter().write(dog);
I have the concept of NodeTypes and Nodes. A NodeType is a bunch of meta-data which you can create Node instances from (a lot like the whole Class / Object relationship).
I have various NodeType implementations and various Node implementations.
In my AbstractNodeType (top level for NodeTypes) I have ab abstract createInstance() method that will, once implemented by the subclass, creates the correct Node instance:
public abstract class AbstractNodeType {
// ..
public abstract <T extends AbstractNode> T createInstance();
}
In my NodeType implementations I implement the method like this:
public class ThingType {
// ..
public Thing createInstance() {
return new Thing(/* .. */);
}
}
// FYI
public class Thing extends AbstractNode { /* .. */ }
This is all well and good, but public Thing createInstance() creates a warning about type safety. Specifically:
Type safety: The return type Thing for
createInstance() from the type
ThingType needs unchecked conversion
to conform to T from the type
AbstractNodeType
What am I doing wrong to cause such a warning?
How can I re-factor my code to fix this?
#SuppressWarnings("unchecked") is not good, I wish to fix this by coding it correctly, not ignoring the problem!
You can just replace <T extends AbstractNode> T with AbstractNode thanks to the magic of covariant returns. Java 5 added support, but it didn't receive the pub it deserved.
Two ways:
(a) Don't use generics. It's probably not necessary in this case. (Although that depends on the code you havn't shown.)
(b) Generify AbstractNodeType as follows:
public abstract class AbstractNodeType<T extends AbstractNode> {
public abstract T createInstance();
}
public class ThingType<Thing> {
public Thing createInstance() {
return new Thing(...);
}
}
Something like that should work:
interface Node{
}
interface NodeType<T extends Node>{
T createInstance();
}
class Thing implements Node{}
class ThingType implements NodeType<Thing>{
public Thing createInstance() {
return new Thing();
}
}
class UberThing extends Thing{}
class UberThingType extends ThingType{
#Override
public UberThing createInstance() {
return new UberThing();
}
}