I know that we can skip casting by adding using the Generics in java as follows. (When we are using it outside of the Generic class.)
But if we are doing some logics on the type object (T item) inside the generic class (Container<T>) we should check the instance of and specially cast isn't it? So we can use it to skip casting out side the generic classes.
Please check the commented code in the public void setItem(T item) method.
I want to know whether my understanding is correct or am I missing something
Client.java
public class Client {
public static void main(String[] args) {
// String container
Container<String> stringContainer = new Container<String>();
stringContainer.setItem("Test");
//stringContainer.setItem(new StringBuffer("")); // compilation error, type safety checking
System.out.println(stringContainer.getItem().toUpperCase()); // No need to cast
// Integer container
Container<Integer> integerContainer = new Container<Integer>();
integerContainer.setItem(123);
//integerContainer.setItem("123"); // compilation error, type safety checking
System.out.println(integerContainer.getItem().intValue()); // No need to cast
}
}
Container class
class Container<T> {
private T item;
public T getItem(){
return item;
}
public void setItem(T item){
/* If I' doing some thing on item then I have to check the instance of and cast isn't it?
if(item instanceof String){
System.out.println("setItem().((String)item).toUpperCase() : " + ((String) item).toUpperCase());
}
*/
this.item = item;
}
}
Reference : http://nandirx.wordpress.com/category/java-2/generics-java/
As others have said, you shouldn't ever downcast a generic type as it defeats the purpose of generics.
You should use bound generics instead. A bound generics allows you to require a generic be of a specific type. This allows you to access values in the specific type without needing to cast.
This doesn't make sense with the String class as String is marked final and so cannot be extended, but for the future, try something like this.
public interface Shape{
double getArea();
}
public class Rectangle implements Shape{
double width;
double height;
public double getArea(){ return width*height;}
}
//this collection can hold Shape, or any type implementing shape.
public class MyShapeCollection<T extends Shape>{
List<T> shapes;
public double getAreaSum(){
double areaSum = 0;
for(Shape s : shapes){
areaSum += s.getArea();
}
return areaSum;
}
}
public static void main(String[] args){
MyShapeCollection<Rectangle> rectangles = new MyShapeCollection<Rectangle>();
//bad code monkey. String does not implement Shape!
//this line won't compile. including it for demonstration purposes.
MyShapeCollection<String> willNotCompile = new MyShapeCollection<String>();
}
If your collection will only hold strings, you don't need generics.
Yes, your understanding is correct.
Adding type specific code here, however, defeats the purpose of generics.
A better solution would be the following.
Client.java
public class Client {
public static void main(String[] args) {
// String container
Container<String> stringContainer = new StringContainer();
stringContainer.setItem("Test");
//stringContainer.setItem(new StringBuffer("")); // compilation error, type safety checking
System.out.println(stringContainer.getItem().toUpperCase()); // No need to cast
}
}
Container.java
class Container<T> {
private T item;
public T getItem(){
return item;
}
public void setItem(T item){
this.item = item;
}
}
StringContainer.java
class StringContainer extends Container<String> {
#Override
public void setItem(String item){
System.out.println( item.toUpperCase() );
super.setItem( item );
}
}
Right, or you could overload the setItem() method for different types of parameters, but that's actually even worse.
Yes, for your case casting is necessary. Because you are using string functions specifically.
But its like you are not using generic feature.
If you wanna to print item, then you can override toString() method of each item, and you can directly put item object in sysout(). By doing so, there will be no casting needed and all code get generic for all items.
What you say here.
Related
I'm trying to create a Variable class that can represent either an Integer or Double value using generics.
Below is the code that I have tried. Because of erasure I use an enum to store the intended type of the Variable and then try and use this to initialise the value to the correct type.
public class Variable<T> {
private enum Type {INTEGER, DOUBLE};
private Type type;
private T value;
public static Variable<Integer> createAsInteger() {
return new Variable<Integer>(Type.INTEGER);
}
public static Variable<Double> createAsDouble() {
return new Variable<Double>(Type.DOUBLE);
}
private Variable(Type type) {
this.type = type;
if(type == Type.INTEGER) {
value = new Integer(0);
} else {
value = new Double(0.0);
}
}
public static void main(String[] args) {
Variable.createAsInteger();
Variable.createAsDouble();
}
}
However when I compile it I get the following message...
error: incompatible types: Integer cannot be converted to T
value = new Integer(0);
and likewise for the Double.
Can anyone explain why this is happening and if there is a way round this without having to write two separate classes, one for Integer and one for Double?
Edit
Thanks for all your answers...based on them I now realise there are better ways of doing this. However I'm trying to get my head round why this approach isn't working so that I don't make the same mistake in the future.
When I define my class as public class Variable<T extends Number> as suggested, I still get the same error.
Your architecture seems to defile the concept of generics.
The simplest way would be to have an upper bound in your type parameter:
class Variable<T extends Number> {...}
Then you can have a generic factory method creating a Variable<X> based on your required class:
static <X extends Number>Variable<X> create() {
return new Variable<X>();
}
You can then invoke it as:
Variable.<Integer>create(); // returns an instance of `Variable<Integer>`
This will not limit to Integer and Double, but rather any Number.
If you have to, you can limit those choices by performing the following:
Add a parameter to your create method: create(Class<X> clazz)
Check the value of your clazz argument within the method's body:
if (!clazz.equals(Integer.class) && !clazz.equals(Double.class)) {
// TODO complain
}
Otherwise, you can ensure you use a private constructor and provide static createAs... non-generic methods such as createAsInteger etc., that would return a new Variable<Integer> etc.
The problem here is that T can be anything. What if T was for instance String, your code would amount to:
String value = new Integer(0);
You could lay out your factory methods like this:
public static Variable<Integer> createAsInteger() {
return new Variable<>(new Integer(0), Type.INTEGER);
}
Where you have a constructor like:
private Variable(T value, Type type) {
this.value = value;
this.type = type;
}
You get the error because you are typizing a method inside a generic class. You can't define some inside the T generic class.
By the way you are mistaking the design pattern.
You have to design a generic class for Variable, also the constructor must have T as argument type.
In an other class you implement the factory with the createInteger and the createDouble methods.
You can make your class inherit from Numbers and use type checking to invoke appropriate method for Integer or Double.
public class Variable<T extends Number> {
public static Variable<T extends Number> Variable<T> create(Variable<T> var){
if (var instanceOf Integer){
// Take appropriate action
}
else if (var instanceOf Double){
// Take appropriate action
}
}
}
By this, there is no peculiar need of maintaining a separate enum for Types.
I'm trying to do something with generics and I can't seem to figure it out. So I have this interface.
public interface Transformation<A,B> {
public B transform(A a);
}
And I have a class that implements it.
public class AveragingTransformer implements Transformation<List<Long>,Double> {
public Double transform(List<Long> a) {
return a.get(0).doubleValue()/a.get(1);
}
}
So in my main method I have this...
public static void main(String[] args){
....
Transformation<List<?>,Double> transformation = new AveraginTransformer();
....
}
But this doesn't work for some reason, can anyone help me understand why?
EDIT
So the issue is if I want to pass an array to my transformation I can't seem to get the compiler to accept it.
So say I have...
public class foo<T>{
T val;
Transformation<? extends List<?>,T> transformation; //This gets initialized by constructor, where I will pass in the averaging transformer in this case.
public void setVal(List<?> list){
val = transformation.transform(list);
}
}
If I try to do this it gives me this error
But I want to keep the left part of my transformation generic because different foos will calculate their values in different ways with potentially different data. i.e. Some foos might calculate their val from a list of Strings but if I provide the right transformer to each, then it should work.
You must match the generics exactly:
Transformation<List<Long>,Double> transformation = new AveragingTransformer();
i.e. change List<?> to List<Long>.
If you want the tool to apply to multiple types then choose an appropriate implemented interface. e.g. here Long implements Number so I will pull back to List<Number>.
public interface Transformation<A, B> {
public B transform(A a);
}
public class AveragingTransformer implements Transformation<List<Number>, Double> {
#Override
public Double transform(List<Number> a) {
return a.stream().mapToDouble(v -> v.doubleValue()).average().orElse(0);
}
}
public void test() {
Transformation<List<Number>, Double> transformation = new AveragingTransformer();
}
Ah so I finally figured it out, as OldCurmudgeon pointed out the issue was the wildcards. The problem was the compiler didn't know that all of them were going to actually be the same in the end, meaning my Foo class actually had another Type parameter I hadn't thought of, the type of the values used to calculate the end result.
public class Foo<T,I>{
T val;
Transformation<List<I>,T> transformation;
public void setVal(List<I> list>){
val = transformation.transform(list);
}
}
public static void main(String[] args){
Foo<Double,Number> foo = nee Foo(new AveragingTransformer());
List<Number> nums = new Arraylist<Number>();
nums.add(2);
nums.add(3);
foo.setValue(nums);
}
Thanks for pointing me in the right direction!
I have a usual interface(that i do not want to make generic) with generic method Get and a generic class, that implements it.
#Override does not give me a warning and the code works as intended, but i have a warning in Foo#Get() :
Type safety: The return type T for Get() from the type Test.Foo<T> needs unchecked conversion to conform to TT from the type Test.Attribute
Must i make Attribute Interface generic as well? I am trying to avoid manual messing with Object and casts and store all types of different attributes in a list.
(using static just to compile the test sample in one file - it does not change anything)
import java.util.ArrayList;
import java.util.List;
public class Test
{
static interface Attribute
{
<TT> TT Get();
}
static class Foo<T> implements Attribute
{
T val;
public Foo(T val)
{
this.val = val;
}
#Override
public T Get()
{
System.out.println("it is me");
return val;
}
}
public static void main(String[] args)
{
List<Attribute> list = new ArrayList<Attribute>();
list.add(new Foo<String>("test"));
String s = list.get(0).Get();
System.out.println(s);
}
}
You could make the Attribute interface generic, and then use a wildcard to allow Attributes of any type to be placed in a List:
List<Attribute<?>> list = new ArrayList<Attribute<?>>();
If you need to ensure that only one Attribute of each type can be placed in the container, just use a Set:
Set<Attribute<?>> set = new HashSet<Attribute<?>>();
In order to use the interface without casting you will need to make the interface generic.
import java.util.ArrayList;
import java.util.List;
public class Test
{
static interface Attribute<E> //Added Generic Param
{
<E> E Get();
}
static class Foo<T> implements Attribute<T> //Added Generic Param
{
T val;
public Foo(T val)
{
this.val = val;
}
#Override
public T Get()
{
System.out.println("it is me");
return val;
}
}
public static void main(String[] args)
{
//Specify Type of generic
List<Attribute<String>> list = new ArrayList<Attribute<String>>();
list.add(new Foo<String>("test"));
String s = list.get(0).Get();
System.out.println(s);
}
}
The problem with the generic method in the base class is that someone could call it with an explicit type parameter. Which obviously would make no sense here, which is why the compiler is complaining.
It seems the best solution is to make your base class generic. If you want to store attributes of different types in a list, then you have a different problem; how are you going to get back to the original types (regardless of whether you're using generics)?
I'm looking through some interfaces at the moment and I'm wondering why this does not work:
interface I {
public void doSomething(String x);
}
class MyType implements I {
public int doSomething(String x) {
System.out.println(x);
return(0);
}
}
Basically, why can't I implement the method in the interface? THey have different signatures as one has a return type? Isn't the name, parameters and return type what make a method unique?
You can't have different return types. Imagine the following
class Foo implements I {
public int doSomething(String x) {
System.out.println(x);
return(0);
}
}
class Bar implements I {
public void doSomething(String x) {
System.out.println(x);
return;
}
}
List<I> l = new ArrayList();
l.add(new Foo());
l.add(new Bar());
for (I i : l) {
int x = i.doSomething(); // this makes no sense for Bar!
}
Therefore, the return types must also be the same!
Yeah, you're basically correct. Java doesn't allow overloading methods by return type, which would be neat. However, the interface return type must still match.
The method signature consists of the method's name and the parameters types, so you can't declare more than one method with the same name and the same number and type of arguments, because the compiler cannot tell them apart.
Think of a typical use for interfaces: e.g. anything implementing the java List interface must implement boolean add(Object o)
The caller is probably going to do something like:
if (!impl.add(o)) { /* report error */ }
If you were allowed to change the return type, you'd hit all types of problems.
void add(Object o)
if (!impl.add(o)) { // ... your method returns void, so this makes no sense
float add(Object o)
if (!impl.add(o)) { // float to boolean ? are you sure that is what you meant?
I'm wondering what are the options to specialize generic types in Java, i.e. in a templated class to have specific overrides for certain types.
In my case I was a generic class (of type T) to return null usually, but return "" (the empty string), when T is the String type, or 0 (zero) when its the Integer type, etc.
Merely providing a type-specific overload of a method produces a "method is ambiguous" error:
e.g.:
public class Hacking {
public static void main(String[] args) {
Bar<Integer> barInt = new Bar<Integer>();
Bar<String> barString = new Bar<String>();
// OK, returns null
System.out.println(barInt.get(new Integer(4)));
// ERROR: The method get(String) is ambiguous for the type Bar<String>
System.out.println(barString.get(new String("foo")));
}
public static class Bar<T> {
public T get(T x) {
return null;
}
public String get(String x) {
return "";
}
}
}
Is the only option to subclass the generic class with a specific type (see StringBar in the following example?
public static void main(String[] args) {
Bar<Integer> barInt = new Bar<Integer>();
StringBar barString2 = new StringBar();
// OK, returns null
System.out.println(barInt.get());
// OK, returns ""
System.out.println(barString2.get());
}
public static class Bar<T> {
public T get() {
return null;
}
}
public static class StringBar extends Bar<String> {
public String get() {
return "";
}
}
}
Is this is the only way, it's a bit of a pain to have to create a subclass for every type I want to specialize instead of an overload of get() in the Bar class.
I'm guessing I could check the instanceof in the Bar.get() method, e.g.
T get(T t) {
if (t instanceof String) return "";
if (t instanceof Integer) return 0;
else return null;
}
However I've been taught to avoid instanceof and use polymorphism when possible.
All things considered, the concensus appears to be that the StringBar method mentioned in the question is the only way to go.
public static class StringBar extends Bar<String> {
public String get() {
return "";
}
}
Generics in Java are very different from templates in C++ in this respect. It is not possible to write a specific version of a generic class to do something different for a particular case, as C++ can do. It is also not possible to determine at run time what T is - this is because that information is not passed into the byte code (object code) and so doesn't even exist at runtime. This due to something called "type erasure".
BarString and BarInt would be the obvious way of doing this, but there are improvements you can make. For example you can write a generic Bar to cover the common cases, and then write specialized BarString and BarInt to implement special cases. Ensure that the instances can only be created through a factory, which takes the class of the object to be processed:
class Bar<T> {
class BarString extends Bar<String> {
// specialist code goes here
}
static Bar<T> createBar(Class<T> clazz) {
if (clazz==String.class) {
return new BarString();
} else {
return new Bar<T>;
}
That probably won't compile, but I don't have the time to work out the exact syntax. It does illustrate the principle.
The compiler is actually correct, because the following code is compile-time checked (Bar<String> barString = new Bar<String>();) when compiled, from
public static class Bar<T> {
public T get(T x) {
return null;
}
public String get(String x) {
return "";
}
}
to
public static class Bar<String> {
public String get(String x) {
return null;
}
public String get(String x) {
return "";
}
}
and is ambiguous as you can't have 2 identical methods with the same return types and the same parameter arguments.
See an explanation by Jon Skeet's:
What is the concept of erasure of generics in java?
Java Generics - Types erasures - when and what happens?
You can subclass Bar<T> and create StringBar (note I removed the static keyword) and override get() method.
public class BarString extends Bar<String> {
#Override
public String get(String x) {
return "";
}
}
Generics in Java aren't made for specialization. They're made for generalization! If you want to specialize for certain types, you should be specializing...through a subclass.
Often you don't need to do something in a specialized manner however. Your StringBar example is kind of contrived because you could have this:
public class Bar<T> {
private final T value;
public T get() {
return value;
}
}
I don't see why you need to specialize for a String here.