namalfernandolk
namalfernandolk

Reputation: 9134

Casting INSIDE the Generic classes in java

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/

Upvotes: 0

Views: 350

Answers (4)

William Morrison
William Morrison

Reputation: 11006

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.

Upvotes: 3

jr.
jr.

Reputation: 1739

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 );
    }
}

Upvotes: 2

rs4706
rs4706

Reputation: 61

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.

Upvotes: 1

Jiri Kremser
Jiri Kremser

Reputation: 12837

Right, or you could overload the setItem() method for different types of parameters, but that's actually even worse.

Upvotes: 1

Related Questions