compile error in generic class - java

why following code doesn't compile ?
class aa1 <String> {
public void fun(){
String s = ""; // not compiling
}
}
class aa2 <String> {
String s = ""; // not compiling
}
class aa3 <String> {
String s = (String)""; // compiling
}
can some tell or give me link for this
thanks.

I think you may have misconstrued the idea behind generics. The point is that your class (aa, in this case) can be... well, generic. It's not of one fixed type, but rather can be any number of types through polymorphism. The generic type is similar to a variable name, but it represents a class, rather than an instance of a class. You could do something like:
class aa <T> {
public void fun(T myObject){
T s = myObject;
}
}
This is an appropriate use of generics. T just represents "some class". The reason the example you posted didn't compile because you overrode the visibility of String (making it the generic type, rather than java.lang.String). If you don't want it to be any class, but some subset of classes, you can do something like:
class aa <T extends MyInterface> {
public void fun(T myObject){
T s = myObject;
}
}
In this case, you're guaranteed that instances of class T also extend the interface MyInterface. However, you cannot extend String, since it's final. If all you wanted was for the String object to be set, you do not need generics at all:
class aa {
public void fun(){
String s = "";
}
}
For more information about generics, read over the Java tutorials on generics.

The generic parameter "String" hides the java.lang.String in this case.
in the class, if you declare the string s and specify its data type as "java.lang.String" then compiler won't complain.
public class aa<String> {
java.lang.String s = "" ;
}

Your code makes no sense - the declaration makes no sense - what are you really trying to do here?
The reason you're having issues compiling is that you're making a generics declaration that's hiding the JDK's java.lang.String.
You're also declaring the same class 3 times. Something like this would compile, but still probably doesn't achieve what you want.
class aa<NotString> {
public void fun() {
String s = ""; // compiles
}
}
class aa2<NotString> {
String s = ""; // compiles
}
class aa3<NotString> {
String s = (String) ""; // compiling
}

Well, it seems that your generic parameter name (String) hides the java.lang.String type.
I would recommend renaming your generic parameter. By the way, which type do you want your s to be: java.lang.String or the same as the parameter? In the latter case, how cuold the compiler assign "" (which is of type java.lang.String) to the potentially irrelevant type represented by the generic parameter?

In your example you are declaring String as an identifier. You must not use keywords or type names. (Generics Tutorial).

Since you're declaring the generic type String, that will override the default java.lang.String type, your code is like typing:
class aa<T> {
T s = "";
}
T is simply Object after type erasure, but since it can be initialized with anything (for example Integer), the compiler won't let you assign Strings to it.

Related

What is the purpose of additional diamond parameters in a method signature (that look like an additional return type(s))? [duplicate]

This question already has answers here:
What does the type parameter <T> in the method definition mean? [duplicate]
(1 answer)
What are Generics in Java? [closed]
(3 answers)
Java Generics: Generic type defined as return type only
(6 answers)
Understanding generic parameters with void return types
(5 answers)
Closed 10 months ago.
I have the following class which builds:
public class Test<T> {
public T DoSomething(T value) {
return value;
}
}
I can also define it like this class like this (notice the extra in the DoSomething signature (which also builds):
public class Test<T> {
public <T> T DoSomething(T value) {
return value;
}
}
What is its purpose and when do I need to include it? I am asking about the additional <T> in the return type, not what generics are.
Maybe this will clear it up. The notation <T> declares a type variable.
So we have one variable T at the class level, and a redeclaration of that same symbol for a particular method.
class Test<T> {
<T> T doSomething(T value) {
// <T> declares a new type variable for this one method
System.out.println("Type of value: " + value.getClass().getSimpleName());
return value;
}
T doSomethingElse(T value) {
// T is not redeclared here, thus is the type from the class declaration
System.out.println("Type of value: " + value.getClass().getSimpleName());
return value;
}
public static void main(String... a) {
Test<String> t = new Test<>();
t.doSomething(42);
t.doSomething("foo"); // also works
t.doSomething(t); // contrived, but still works
t.doSomethingElse("hi");
t.doSomethingElse(42); // errors because the type `T` is bound to `String` by the declaration `Test<String> t`
}
}
In main, I create a Test<String> so the class-level T is String. This applies to my method doSomethingElse.
But for doSomething, T is redeclared. If I call the method with an Integer arg, then T for that case is Integer.
Really, it would have been better to call the second type variable anything else at all, on the declaration of doSomething. U, for example.
(In most cases, I actually favour giving useful names to type variables, not just single letters).
The concept is known as a generic method (docs.oracle.com).
In the code presented, we have an especially tricky case of generics since we have two generic parameters with the same name:
the <T> on the class-level: public class Test<T>, and
the <T> on the method-level: public <T> T DoSomething(T value)
The latter hides the former within the scope of the method DoSomething(...), just like a local variable would hide an instance field with the same name. In general, I would advice against this type of "hiding" since it makes the code harder to read and understand. Thus, for the rest of the discussion we will work with this (slightly modified) version of the code:
public class Test<T> {
public T doSomethingWithT(T t) {
return t;
}
public <U> U doSomethingWithU(U u) {
return u;
}
}
The scope of the class-level generic parameter T is for the whole class, while the scope of the method-level generic parameter U is only for the one method it is delared on. This will lead to the following observation:
// T is bound to type String for the instance testString:
final Test<String> testString = new Test<>();
final String tString = testString.doSomethingWithT("Hello");
System.out.println(tString); // prints "Hello"
// will not compile since 1 is not a String:
// int tInt = testString.doSomethingWithT(1);
// For this one invocation of doSomethingWithU(...), U is bound to
// type String:
final String uString = testString.doSomethingWithU("World!");
System.out.println(uString); // prints "World!"
// for this one invocation of doSomethingWithU(...), U is bound to
// type Integer:
final int uInt = testString.doSomethingWithU(1);
System.out.println(uInt); // prints "1"
Ideone demo
Notice that, although doSomethingWithU(...) is a generic method, we did not have to specify the generic parameter, the compiler inferred the type for us. While seldom used, we can also explicitly specify the generic parameter for thie method:
final Test<String> testString = new Test<>();
final Number number = testString.<Number>doSomethingWithU(1);
System.out.println(number);
Ideone demo
(In this example, the explicit generic parameter is not necessary, the code works without it aswell, but there are rare cases where this may be useful or even necessary.)
The following is not strictly necessary to understand generic methods, but more of a curiosity one might find in code and is meant to prime the reader that it is bad practice, should not be used and removed when seen.
It should also be mentioned that the JLS allows us to add generic method parameters on method invocations that do not have any generic parameter. Those parameter do not have any effect:
Object o = new Object();
// Method "hashCode()" on "Object" has not generic parameters, one
// can "add" one to the method invocation, it has no effect on the
// semantics, however
int hash = o.<String>hashCode();
Ideone demo
A remark on the code: In Java, methods should be written in camelCase instead of CamelCase (DoSomething(...) -> doSomething(...))

Parameterize a class with one of a fixed set of types

Say I have a generic class Foo which can hold an object of type T. Furthermore, let's say I only want to be able to instantiate the class with objects that are one of two types. Finally, let's say that the lowest common upper bound of these two types is a type that has many more subclasses than those two types that I want to allow, so I can't simply specify an upper bound for the type parameter (as in class Foo<T extends Something>), because then I would allow to instantiate the class with other types than the two I expect.
For illustration, let's say I want Foo to hold only either a String or an Integer. The lowest common upper bound is Object, so specifying an upper bound won't do the trick.
Certainly, I could do something along the lines of
class Foo<T> {
private T obj;
public Foo(T obj) throws IllegalArgumentException {
if (!(obj instanceof String || obj instanceof Integer)) {
throw new IllegalArgumentException("...");
}
this.obj = obj;
}
}
However, in this case, I can still call the constructor with any object; if I try to instantiate it with something that is neither a String nor an Integer, I will get an exception at runtime.
I would like to do better. I would like the compiler to infer statically (i.e., at compile time) that I can only instantiate this class with objects that are either String or Integer.
I was thinking something along those lines might do the trick:
class Foo<T> {
private T obj;
public Foo(String s) {
this((T) s);
}
public Foo(Integer i) {
this((T) i);
}
private Foo(T obj) {
this.obj = obj;
}
}
This works, but it looks really, really odd. The compiler warns (understandably) about unchecked casts. Of course I could suppress those warnings, but I feel this is not the way to go. In addition, it looks like the compiler can't actually infer the type T. I was surprised to find that, with the latter definition of class Foo, I could do this, for instance:
Foo<Character> foo = new Foo<>("hello");
Of course, the type parameter should be String here, not Character. But the compiler lets me get away with the above assignment.
Is there a way to achieve what I want, and if yes, how?
Side question: why does the compiler let me get away with the assignment to an object of type Foo<Character> above without even so much as a warning (when using the latter definition of class Foo)? :)
Try using static factory method to prevent compiler warning.
class Foo<T> {
private T obj;
public static Foo<String> of(String s) {
return new Foo<>(s);
}
public static Foo<Integer> of(Integer i) {
return new Foo<>(i);
}
private Foo(T obj) {
this.obj = obj;
}
}
Now you create instance using:
Foo<String> foos = Foo.of("hello");
Foo<Integer> fooi = Foo.of(42);
Foo<Character> fooc = Foo.of('a'); // Compile error
However the following are still valid since you can declare a Foo of any type T, but not instantiate it:
Foo<Character> fooc2;
Foo<Character> fooc3 = null;
Foo<Object> fooob1;
Foo<Object> fooob2 = null;
one word: interface. You want your Z to wrap either A or B. Create an interface implementing the smallest common denominator of A and B. Make your A and B implement that interface. There's no other sound way to do that, AFAIK. What you already did with your constructors etc. is the only other possibility, but it comes with the caveats you already noticed (having to use either unchecked casts, or static factory wrappers or other code smells).
note: If you can't directly modify A and/or B, create wrapper classes WA and WBfor them beforehand.
example:
interface Wrapper {
/* either a marker interface, or a real one - define common methods here */
}
class WInt implements Wrapper {
private int value;
public WInt( int value ) { this.value = value; }
}
class WString implements Wrapper {
private String value;
public WString( String value ) { this.value = value; }
}
class Foo<T> {
private Wrapper w;
public Foo(Wrapper w) { this.w = w; }
}
because you call your private Foo(T obj) due to diamond type inference. As such, it's equal to calling Foo<Character> foo = new Foo<Character>("hello");
Long story short: You are trying to create a union of two classes in java generics which is not possible but there are some workarounds.
See this post
Well the compiler uses the Character class in T parameter. Then the String constructor is used where String is casted to T (Character in this case).
Trying to use the private field obj as a Character will most likely result in an error as the saved value is an instance of the final class String.
Generics is not suitable here.
Generics are used when any class can be used as the type. If you only allow Integer and String, you should not use generics. Create two classes FooInteger and FooString instead.
The implementations should be pretty different anyway. Since Integers and Strings are very different things and you would probably handle them differently. "But I am handling them the same way!" you said. Well then what's wrong with Foo<Double> or Foo<Bar>. If you can handle Integer and String with the same implementation, you probably can handle Bar and Double and anything else the same way as well.
Regarding your second question, the compiler will see that you want to create a Foo<Character>, so it tries to find a suitable overload. And it finds the Foo(T) overload to call, so the statement is perfectly fine as far as the compiler is concerned.

Java equivalent of Objective-C instancetype?

In Objective-C, instancetype can be used as the return type of methods that return an instance of the class they are called on (or a subclass of that class).
What is the equivalent of instancetype in Java?
The closest to thing is to use generics
interface Base<B extends Base<B>> {
// do something and return this.
B append(String s);
}
interface SubBase<B extends SubBase<B>> extends Base<SubBase<B>> {
// append returns a SubBase<B>
}
class MyClass implements SubBase<MyClass> {
public MyClass append(String s) {
// do something
return this;
}
}
It's not so elegant, but it works.
If you mean something like this:
class Vehicle {
instancetype doNothing() {return this;}
}
class Car extends Vehicle {}
Car c = new Car().doNothing(); // no compile errors here
There is no equivalent.
One workaround that's sometimes used is to pass the type as a generic parameter:
class Vehicle<instancetype> {
instancetype doNothing() {return this;}
}
class Car extends Vehicle<Car> {}
Car c = new Car().doNothing(); // works
but then you can't use the type Vehicle without getting warnings everywhere (it has to be Vehicle<?>).
I'm no Javaist but likely there is no equivalent, because Java needs it only rarely. (And Objective-C do so, too.)
Please note that in Objective-C you do not need it most of the time, too. This is, because the compiler infers the "real" return type from the receiver, even it is declared id. This applies to -init…, +alloc…, -new…:
To determine whether a method has an inferred related result type, the first word in the camel-case selector (e.g., “init” in “initWithObjects”) is considered, and the method will have a related result type if its return type is compatible with the type of its class and if:
the first word is “alloc” or “new”, and the method is a class method, or
the first word is “autorelease”, “init”, “retain”, or “self”, and the method is an instance method.
In Java this is inferred for the new operator, too. The constructors does not have any return type, so it does not need to be inferred.
Up to here: No need for an (explicit) keyword in Java or Objective-C.
In some cases you have additional methods returning a new instance of the receivers class. Cloning/copying is such a case. In Java you have to type cast the result. In Objective-C you can use instancetype to make code easier to read. (BTW: NSObject's -copy has id as return type, not instancetype. But again usually this is no problem, because you typically assign the return value to a typed reference.)
So the short conclusion: In both Java and Objective-C the return type can be and is inferred by the compiler for most of the use cases. In rare use cases you have to explicitly cast in Java.

java class declaration with the generic type disable method returning another generic type

I have this little problem and I want to find out whay is this happening to me:
I made class like this:
public class SomeSimpleClass {
//and I had method who returns generic. it can be instance of whatever, and for sure can be casted to U:
public <U>U giveMeSomething(String arg) {
return (U)SomewhereSomething.getValueCastingIsOK(arg);
}
}
and then I am using it like this:
// give me some number:
Integer number = instanceSomeSimpleClass.giveMeSomething("I want integer value");
OR
String text = instanceSomeSimpleClass.giveMeSomething("I want text now");
and everything is ok. getValueCastingIsOK from SomewhereSomething returns me what I want, and I dont need type cast on the giveMeSomething. Looks like the U is replaced by the type from the associative variable.. and everything is cool..
BUT then I create a new class:
public class SomeOtherClass <T extends Something> {
//And I have the exactly same method here:
public <U>U giveMeSomething(String arg) {
return (U)SomewhereSomething.getValueCastingIsOK(arg);
}
}
and now when I want to use it in the same way, the compiler (I am using Java 1.7) is telling me, that I have to use typecast, and start to using the giveMeSomething like this, because U is now the Object, and nothing else...
Integer number = (Integer)instanceSomeSimpleClass.giveMeSomething("I want integer value");
:(
Why in the second case the compiler cant get the U type in the same way, as in the first case. And what I have to do, to be that this way?
Thank for an answers, suggestions.. ;)
The problem is that you're using a raw type of the class SomeOtherClass, but not supplying any type parameters to your declaration:
SomeOtherClass instanceSomeSimpleClass = new SomeOtherClass();
When you do this, the Java compiler will replace ALL generics in the class with the type erasure version, even unrelated generics such as your generic method. The type erasure of the method
public <U>U giveMeSomething(String arg) {
becomes
public Object giveMeSomething(String arg) {
which requires the cast to Integer.
You must either supply a type parameter to SomeOtherClass (useless, unless you've eliminated unnecessary code that uses T to post the class code here):
SomeOtherClass<Something> instanceSomeSimpleClass = new SomeOtherClass<Something>();
Or you can remove the type parameter on the class definition, as you had it originally:
public class SomeSimpleClass {
Either will keep the generic method intact and eliminate the need to cast the return type of giveMeSomething.
You're missing the java syntax for explicit typing:
public <U>U giveMeSomething(String arg) {
return SomewhereSomething.<U>getValueCastingIsOK(arg);
}
Notice the <U> between the dot and the method name. Notice also that casting is now not required.
That's how you explicitly declare what the type is for a typed method. Without this, java must infer the type, which it can't here, so (unsafe) casting is required.
Another example to illustrate. In this case, java can infer the type is Integer because of the type that the result is being assigned to:
Integer number = instanceSomeSimpleClass.giveMeSomething("I want integer value");
But if you were to use the value without assigning it, you'd need to pass to type:
someIntegerRequired(instanceSomeSimpleClass.<Integer>giveMeSomething("I want integer value"));

Generics in Java, using wildcards

I have a question about Generics in Java, namely using wildcards. I have an example class GenClass like this:
public class GenClass<E> {
private E var;
public void setVar(E x) {
var = x;
}
public E getVar() {
return var;
}
}
I have another simple class:
public class ExampleClass {
}
I have written the following test class:
public class TestGenClass {
public static void main(String[] str) {
ExampleClass ec = new ExampleClass();
GenClass<ExampleClass> c = new GenClass<ExampleClass>();
c.setVar(ec);
System.out.println(c.getVar()); // OUTPUT: ExampleClass#addbf1
}
}
Now, if I use a wildcard and write in the test class this:
GenClass<?> c = new GenClass<ExampleClass>();
on the place of:
GenClass<ExampleClass> c = new GenClass<ExampleClass>();
the compiler has no problem with this new statement, however, it complains about
c.setVar(ec);
It says that "the method (setVar()) is not applicable for the arguments (ExampleClass)". Why do I get this message?
I thought that the way I have used the wildcard, makes the reference variable c be of type GenClass, which would accept as parameter any class - on the place of E I would have any class. This is just the declaration of the variable. Then I initialize it with
new GenClass<ExampleClass>()
which means that I create an object of type GenClass, which has as parameter a class of type ExampleClass. So, I think that now E in GenClass will be ExampleClass, and I would be able to use the method setVar(), giving it as argument something of type ExampleClass.
This was my assumption and understanding, but it seems that Java does not like it, and I am not right.
Any comment is appreciated, thank you.
This exact situation is covered in the Java Generics Tutorial.
Notice that [with the wildcard], we can still read elements from [the generic Collection] and give them type Object. This is always safe, since whatever the actual type of the collection, it does contain objects. It isn't safe to add arbitrary objects to it however:
Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error
Since we don't know what the element type of c stands for, we cannot add objects to it. The add() method takes arguments of type E, the element type of the collection. When the actual type parameter is ?, it stands for some unknown type. Any parameter we pass to add would have to be a subtype of this unknown type. Since we don't know what type that is, we cannot pass anything in. The sole exception is null, which is a member of every type.
(emphasis mine)
mmyers has the correct answer, but I just wanted to comment on this part of your question (which sounds like your rationale for wanting to use the wildcard):
I thought that the way I have used the wildcard, makes the reference variable c be of type GenClass, which would accept as parameter any class - on the place of E I would have any class. This is just the declaration of the variable. Then I initialize it with
If you really want to accomplish this, you could do something like without compilation errors:
GenClass<Object> gc = new GenClass<Object>();
gc.setVar(new ExampleClass());
But then again, if you want to declare an instance of GenClass that can contain any type, I'm not sure why you'd want to use generics at all - you could just use the raw class:
GenClass raw = new GenClass();
raw.setVar(new ExampleClass());
raw.setVar("this runs ok");

Categories