How generics helping in this scenario? - java

Going through generics at generics and got this question
public class Box<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
If i want box to hold only integer i can initiate like below . Makes sense here.
Box<Integer> integerBox = new Box<Integer>();
case 2:-
But at various place i have seen following below pattern
public class Box<Integer> {
private Integer var;
public void set(Integer var) { this.var = var; }
public Integer get() { return var; }
}
The way of instantiation is same i.e
Box<Integer> integerBox = new Box<Integer>();
But how instantiating with integer helps here as we are not using it ?
I am not getting what benefit we are getting with generic specifier along with class declaration in second case?
I mean if i declare class without diamond operator in second case, what the benefit i am losing ? I am sure i am but not hitting the right spot .
Edit :-
Looks like i was not clear in case 2 snippet. Please refer below code snippet
public class Box<Integer> {
private String var;
public void set(String var) { this.var = var; }
public String get() { return var; }
}

What you see at "various places" is just bad coding. Integer in
public class Box<Integer>
is not a reference to the java.lang.Integer class, but a generic type variable, just like T was. As such, it shadows java.lang.Integer type inside the class definition. In fact, the two snippets you posted are exactly the same.
Just run the following piece of code, if you are not convinced:
public class Demo {
public static void main(String args[]) {
Box<String> a = new Box<>();
a.set("dummy");
a.whatami();
}
}
class Box<Integer> {
private Integer var;
public void whatami() {
System.out.println(var.getClass().getName());
}
public void set(Integer var) { this.var = var; }
public Integer get() { return var; }
}
Output will be java.lang.String, not java.lang.Integer.
In fact, you are not required to name the generic type T. You can call it Foo, Bar, Baz. Maybe avoiding misleading names could be a good idea. Maybe.
EDIT: your edit completely changes the question. In that specific case, you get no advantage from declaring a generic that does not use the generic type variable. Neither you get any disavantage, because of compile time type erasure.
But, it's not completely pointless. Although the class does not use the type tag now, it might use it in a future version. And if you get to the a point where you need to make your class generic, you will have to go through all the code you wrote until that moment and amend it with the diamond notation. It will cost you time and you might also have to refactor certain parts.

Related

Why generic type parameter get method throws NullPointerException

I have this simple Java class and I am just trying to pass the Type but I get always a Nullpointer Exception cause null is obviously Null WHY?
public class Main {
public static void main(String[] args) {
Box<String> test = new Box<>();
test.print();
}
//And the Generic Class
public class Box<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
public void print () {
System.out.println(this.t.getClass());
}
}
Using JDK 12
You get NullPointerException because reference of t variable is null. You are trying to access the variable before initialize it. Firstly, call the setter method. Then try to get it.
NullPointerException: NullPointerException Thrown when an application attempts to use null in a case where an object is required.
Here is the solution
Box<String> test = new Box<>();
test.set("hi!");
test.print();
Whilst all other answers explain why you get the NullPointerException, it's clear you want to retrieve, one way or another, the String bit of your Box<String> expression.
You can't; this is called erasure. Generics in expressions and local variable declarations are figments of the compiler's imagination; they are compiler-checked comments. Like comments. they cease to exist at runtime.
Generics in signatures (so, method return types, parameter types, types of fields, and any generics mentioned anywhere in your class declaration line, so, the A, B, and C in class Foo<A> extends Parent<B> implements Something<C>) are recoverable using some very tricky and weird API (and you really don't want to, I think).
If you must be able to access single simple types, I suggest passing in the actual class object: new Box<String>(String.class).
You only new a Object Box<String> ,however you didn't initialize the private T t;
try something like this
Box<String> test = new Box<>();
test.set("the first way");
test.print();
or
public class Main {
public static void main(String[] args) {
Box<String> test = new Box<>("the second way");
test.print();
}
public class Box<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
public Box(T t) {this.t = t}
public void print () {
System.out.println(this.t.getClass());
}
}
You only initialize your Box<String> object, but you didn't set the T t instance variable to anything.
As T is an Object its default value will be null.
Try setting it first, then calling print.
Box<String> test = new Box<>();
test.set("test");
test.print();

What does public<T> void run (T object ) { } means? [duplicate]

This question already has answers here:
Return Type of Java Generic Methods
(5 answers)
Closed 6 years ago.
I am reading generics and tried writing the below code. There are no compilation error.
import java.util.*;
public class JavaApplication14 {
public<T> void run (T obj ) {
//Do Something
}
public static void main(String[] args) {
JavaApplication14 m= new JavaApplication14();
m.run(new ArrayList<>());
m.run(new Interger(5);
m.run(5);
}
}
If the function is
public<T extends Number> void run (T obj) {
//Do Something
}
It makes sense as we can restrict the arguments of this function to a Number and its subtypes. But am terribly confused what the function 'run' without any bound mean?
Can it now take any object as the argument ? In what scenario do i need to use such a function with generics ?
Part of your confusion may stem from the fact that there is no point in having run be a generic method in this case. You normally use a type parameter to create a relationship between two parameter types and/or between parameter type and return type. In your example run could just as well have been declared as requiring an Object parameter (a type parameter without a declared bound effectively has Object as its bound).
There is one case I know of where you might usefully use a type parameter in a single parameter type: when you want to be able to manipulate a collection in a way that doesn't depend on the element type, but which does require inserting elements into the collection. Consider for example a hypothetical "reverse list" method:
<T> void reverse(List<T> list)
{
List<T> reversed = new ArrayList<T>();
for (int i = list.size(); i > 0; i--) {
reversed.add(list.get(i - 1));
}
list.clear();
list.addAll(reversed);
}
It would be difficult to write this in a way that didn't require a type parameter, i.e. that takes a List<?> parameter. The only way to do it without casts is to do:
void reverse2(List<?> list)
{
reverse(list); // call reverse as defined above!
}
But again, this doesn't apply in the example you discuss.
So in summary:
A type parameter without an explicit bound effectively has an Object bound.
There are two reasons why a method might need a type parameter (either with or without an explicit bound):
Specify a relationship between parameter types and/or return type
Capture a potential wildcard as a type parameter to allow operations that wouldn't otherwise be possible (as in the reverse example).
The example method you discussed:
public<T> void run (T obj )
... does neither of these, and so the type parameter is pointless. The method might just as well have been declared as public void run(Object obj).
It allows you to avoid any cast.
public class SomeClass {
void doStuff();
}
public<T extends SomeClass> void run (T obj) {
//can call doStuff without any casting
obj.doStuff();
}
public<T> void run (T) {
//Here, there's no clue to perform the implicit cast.
obj.doStuff(); //won't compile
}
While in this case the function could take Object just as well, the variant that makes sense to you is equivalent to public void run(Number obj) { ... } as well. For an example where lack of bound makes sense consider a case where the return type mentions T: public <T> List<T> singletonList(T obj).
Some theory
There're generic methods. Their main goal is generic algorithms (receive and return same types).
Code that uses generics has many benefits over non-generic code:
Elimination of casts.
Stronger type checks at compile time.
Enabling programmers to implement generic algorithms.
A little practice
Consider the following code:
class MyClass {
public void method() {}
public static void main(String[] args) {
runFirst(new MyClass());
runSecond(new MyClass());
}
public static <T extends MyClass> void runFirst(T obj) {
obj.method();
}
public static <T> void runSecond(T obj) {
((MyClass) obj).method();
}
}
The runFirst() method allows us to avoid cast to class and all its subclasses. In runSecond() method we can get any type of parameter (<T>, roughly speaking, means <T extends Object>). Firstly, we must cast to MyClass and then call its method.
First of all I will start with the meaning of public <T> void run(T object) { ... }. Yes when you use that kind of code you than you may use any object as a parameter of run. If you want to restrict the arguments of this function to a specific interface, class or its sub classes you can just write code like NotGenericRun which is shown below.
public class NotGenericRun {
public void run(ArrayList<?> list) {
String message = "Non Generic Run List: ";
System.out.println(message.concat(list.toString()));
}
public void run(int intValue) {
String message = "Non Generic Run Int: ";
System.out.println(message.concat(String.valueOf(intValue)));
}
}
Here I tested output of GenericRun and NotGenericRun classes.
public class TestClass {
public static void main(String[] args) {
GenericRun m = new GenericRun();
m.run(new ArrayList<>());
m.run(new Integer(5));
m.run(5);
NotGenericRun n = new NotGenericRun();
n.run(new ArrayList<>());
n.run(new Integer(5));
n.run(13);
}
}
Output of this code was following:
Generic Run: []
Generic Run: 5
Generic Run: 5
Non Generic Run List: []
Non Generic Run Int: 5
Non Generic Run Int: 13
When you use Generic run as I already said arguments may be any object but there is other way of restricting the arguments while still using generics.
public class GenericRun {
public <T> void run(T object) {
String message = "Generic Run: ";
System.out.println(message.concat(object.toString()));
}
}
This is how.
public class GenericRun <T> {
public void run(T object) {
String message = "Generic Run: ";
System.out.println(message.concat(object.toString()));
}
}
In this case you'll be using GenericClass like this:
GenericRun<Integer> m = new GenericRun<Integer>();
m.run(new Integer(5));
m.run(5);
and only value that it will be tacking should be stated while creating class. I can't think of scenario when public <T> void run(T object) { ... } may be needed but it might occur when you'll need the method to get every argument or you don't know what arguments will be (but it's really less likely). I think more often when you'll be using generics with run like this:
public class GenericRun <T> {
public void run(T object) {
...
}
}
I was searching about usage of generic methods here you can read more about why may we need generic methods.
Here is another example:
public class GenericRun {
public <T> void run(T[] inputArray) {
for (T element : inputArray) {
System.out.printf("%s ", element);
}
System.out.println();
}
}
Using this class you can print array of different type using a single Generic method:
public class TestClass {
public static void main(String[] args) {
GenericRun m = new GenericRun();
// Create arrays of Integer, Double and Character
Integer[] intArray = { 1, 2, 3, 4, 5 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
System.out.println("Array integerArray contains:");
m.run(intArray); // pass an Integer array
System.out.println("\nArray doubleArray contains:");
m.run(doubleArray); // pass a Double array
System.out.println("\nArray characterArray contains:");
m.run(charArray); // pass a Character array
}
}
I hope I answered your question.
The only thing makes sense here is if this was some kind of pseudo-abstract or base class, that provided framework for behaviour and let another coders implement their own logic, but also provided default null action.
It could allow for better generic type-setting, for example as:
class MySubClass extends JavaApplication14 {
public <T> void run(T obj){
new ArrayList<T>().add(obj);
}
}

problems with understanding generics

I have wrote the following code:
public class Test
{
public static void main(String args[]) throws ParseException
{
System.out.println(new Generic<Integer>("one").type); //outputs "one"
}
}
class Generic<T>
{
public T type;
public Generic(Object obj)
{
type = (T)obj;
}
}
And i thought i will get an exception while doing the cast, but i didnt. I get the output: "one". But if i do new generic<Integer>, type become a variable of type Integer, so how can i cast the String "one" to T and store it in the variable type in my generic class without getting an exception? An explanation would be great.
There is no exception because type erasure removes any checking of the Integer type from your code. Since println takes Object the compiler doesn't need to insert a cast, and the code simply erases to:
System.out.println(new Generic("one").type);
Try the following assignment instead:
Integer i = new Generic<Integer>("one").type;
In that case you'll get a ClassCastException because the code erases to:
Integer i = (Integer)new Generic("one").type;
Notice that switching the types behaves differently. This will throw a ClassCastException:
System.out.println(new Generic<String>(123).type);
That's because the println(String) overload is used, so the code erases to:
System.out.println((String)new Generic(123).type);
This is because of java type erasure:
http://docs.oracle.com/javase/tutorial/java/generics/erasure.html
basically java will replace T with Object (if T has no bounding upper type like in your example)- and everything is fine at runtime.
It is not casting your string to integer....because it is unbound. It is converting the T to object instead and in the sysout you are getting obj.toString instead.
The proper way would be as below and automatically you will get compile exception in your test class... as expected.
class Generic<T>
{
public T type;
public Generic(T t)
{
type = t;
}
}
class Generic<T>
{
public T type;
public Generic(T obj)
{
type = obj;
}
}
There. Fixed it for you.

T does not understand `java.lang.reflect.Type`or java.lang.Class<T>

I want my T type to be instance of java.lang.reflect.Type interface or java.lang.Class<T>
I have created sample code like below
public class Car<T extends Type> {
private T t;
public Car(T t) {
this.t = t;
}
public static void main(String[] args) {
Car<String.class> car = new Car(String.class);//Error String.class
}
}
I know above in above example I can use Class<T> instead of using T. I wanted to know if there is any way in which T can be made to understand that it is of Type or Class?
Instead of Car<String.class>, write Car<Class<String>>.
String.class is an object. Between the angle brackets you must specify a type. The type you're looking for is Class<String>.

Why the generic method changed the parametrized type in an assignation?

When writing a generic method to process data for a form, I came across with the following (as I see it) unexpedted behavior. Given the following code:
public class Test {
public <T> void someGenericMethod(Integer a) {
#SuppressWarnings("unchecked")
T t = (T) a;
System.out.println(t);
System.out.println(t.getClass());
}
public static void main(String[] args) {
Test test = new Test();
test.<BigDecimal>someGenericMethod(42);
}
}
AFAIK, the code above should generate a ClassCastException in the line T t = (T) a because the method call in main is setting the parametrized type to BigDecimal and casting from Integer to BigDecimal is not allowed, conversely to what I expected, the program executed well and printed the following:
42
class java.lang.Integer
In fact, if I add another parameter to the method signature (like String b) and make another assigment T t2 = (T) b, the program prints
42
class java.lang.String
Why the t variable changed it's type to Integer (is, by any chance, making some kind of promotion on the type T to Object)?
Any explanation on this behavior is welcome
(T) a is an unchecked cast: due to type erasure, the runtime has no way of knowing what type T is, so it can't actually check if a belongs to type T.
The compiler issues a warning when you do this; in your case, you've suppressed that warning by writing #SuppressWarnings("unchecked").
Edited to add (in response to a further question in the comments below):
If you want to check the cast, you can write this:
public class Test {
public <T> void someGenericMethod(Class<T> clazz, Integer a) {
T t = clazz.cast(a);
System.out.println(t);
System.out.println(t.getClass());
}
public static void main(String[] args) {
Test test = new Test();
// gives a ClassCastException at runtime:
test.someGenericMethod(BigDecimal.class, 42);
}
}
by passing in clazz, you allow the runtime to check the cast; and, what's more, you allow the compiler to infer T from the method arguments, so you don't have to write test.<BigDecimal>someGenericMethod anymore.
Of course, the code that calls the method can still circumvent this by using an unchecked cast:
public static void main(String[] args) {
Test test = new Test();
Class clazz = Object.class;
test.someGenericMethod((Class<BigDecimal>) clazz, 42);
}
but then that's main's fault, not someGenericMethod's. :-)
When compiling, your code above basically becomes the following non-generic method:
public void someGenericMethod(Integer a) {
Object t = a;
System.out.println(t);
System.out.println(t.getClass());
}
There is no cast. No exception.
You specify a type parameter in your method signature, but never use it.
I think you want something like this:
public class Test {
public <T> void someGenericMethod(T someItem) {
System.out.println(someItem);
System.out.println(someItem.getClass());
}
}
public static void main(String[] args) {
Test test = new Test();
BigDecimal bd = new BigDecimal(42);
test.someGenericMethod(42); // Integer
test.someGenericMethod("42"); // String
test.someGenericMethod(42L); // Long
test.someGenericMethod(bd); // BigDecimal
}
Note that there's no need to cast.
The parameter type is declared in the method signature and inferred from the parameter.
In your code you're parameterizing the method call (which I've never seen) and passing in an int.
It's kinda hard to understand what you're trying to do, since your example code does nothing.

Categories

Resources