It seems for a good reason I need to switch to Scala! So, excuse me if my question might seem novice.
It seems that Any in scala is the supper class of all types and might be considered as an Object type equivalent in Java. But type Any is abstract, while Object is not. More concretely, I can not write the following code in scala (since class Any is abstract and cannot be instantiated):
val k:Any = new Any();
while I can write the following code in Java:
Object k=new Object();
What should I use if I need a concrete equivalent type of java Object type?
AnyRef type which is not abstract seems to be the equivalent of the Java Object Class (see this)
so the following works in scala:
val k:AnyRef = new AnyRef();
AnyRef is the equivalent of java's Object. (Scala unifies the type system rather than having the object/primitive distinction that Java has. So an instance of Any might be a descendant of Object/AnyRef, or an instance of a Java primitive type (e.g. int). (Or it could also be a "value class" descending from AnyVal)).
Related
In Java, I can do that:
class JavaClass<A, B>{
A first;
B second;
}
And then declare an array, a list, or a single object of that type, without supplying generic parameters. They're being automatically converted to Object's, like in an example below:
JavaClass someArray = new JavaClass[4];
Now, the type of someArray[0].first is Object.
In C#, it doesn't seem to work:
class Leaderboard<UserType, UIEntry>
where UserType : User
where UIEntry : UserUIEntry{}
And the declaration:
Leaderboard someLeaderboard = new Leaderboard();
Gives:
Using the generic type Leaderboard requires two type arguments.
Is there any equivalent to make this work and allow me to declare that?
First of all, generics in C# and Java are very different, both conceptually and implementation-wise. C# has so-called reified generics, while Java uses type erasure. Therefore, looking for similarities between these two languages in generics is usually not a good idea.
In C#, Leaderboard and Leaderboard<UserType, UIEntry> are two distinct types. If you really want to, you can write
class Leaderboard<UserType, UIEntry>
where UserType : User
where UIEntry : UserUIEntry{}
class Leaderboard : Leaderboard<User, UserUIEntry>{}
and then use just new Leadeboard() (relying on inheritance). However, I wouldn’t think this is an especially great idea, trading a few keystrokes for worse readability.
Look how e.g. Tuple does it: Tuple is a nongeneric helper for the generic Tuple<...> class, containing a static .Create function which helps with type inference, reducing the need to write the generic parameters explicitly.
Sorry for the wordy title :) Here is the Scala object:
object TokenPosition extends java.lang.ThreadLocal[Int]
And here is the Java code that uses it:
TokenPosition$.MODULE$.set(position);
Eclipse gives me the following warning:
Type safety: The method set(Object) belongs to the raw type ThreadLocal. References to generic type ThreadLocal<T> should be parameterized
What should I do? Or is this an inherent limitation of Generics and Java/Scala interop?
Try changing Int to Integer, Int is like Java's int, and Integer is a wrapper, so it should help.
I'm converting someone else's java code to scala (for the curious, it's the example here) and I hit a compiler error on the following (simplified somewhat):
var out = new Formatter(new StringBuilder(), Locale.US)
out.format("%s-%d ", someObject, someInteger);
And here's the error message I get:
[error] (java.util.Locale,java.lang.String,<repeated...>
[java.lang.Object])java.util.Formatter <and>
[error] (java.lang.String,<repeated...>[java.lang.Object])java.util.Formatter
[error] cannot be applied to (java.lang.String, java.lang.Object, Int)
...
[error] one error found
This works if I change the second line to:
out.format("%s-%d ", someObject, someInteger.asInstanceOf[Object]);
Can someone explain why this is?
Does this mean that it's ok in java to pass integers where object arguments are expected but not in scala?
The other answers all add something, but I'm not sure they explain what the problem is.
It all comes down to Int being a class in Scala while int is a primitive in Java. So, in Java, when you write that a method expects an Object, and you pass an int, Java will auto-box it in a java.lang.Integer.
Now, Java's java.lang.Object equivalent in Scala is AnyRef, but Int is not a subclass of AnyRef. There's a proper type for that: Any. An Any can contain both things which are subclasses of java.lang.Object as well as the stuff that are primitives in Java. If you say a method expects Any and pass an Int, then it will be auto-boxed, but not for AnyRef.
So, whenever you interface with Java and a method expects you to pass boxed primitives, you'll have to force the boxing yourself. You can create a method expecting Any in Scala, and then cast it to AnyRef and call the Java equivalent, to make things easier if you are going to call that method a lot.
The class hierarchy isn't the same in java and scala. java.lang.Object is at the root of the hierarchy in java. In scala, the Any type is at the root. So, anything can be passed to a function which takes a parameter of type Any. However, only subtypes of java.lang.Object can be passed to a function which takes a parameter of type java.lang.Object.
To make matters worse, there's two types of integers. There's scala's Int type, and java.lang.Integer. The former is what you usually get when you set something to a number literal in scala. The latter is what you get with new Integer(3) or 3.asInstanceOf[Integer]. It turns out that the scala Int does not inherit from java.lang.Object, but java.lang.Integer does inherit. As a result you can't pass a scala Int as a parameter expecting a java.lang.Object. That's why this doesn't work in scala.
Java's story is a little weird. In the past it used to be that java ints couldn't be passed where an object was expected; you needed to explicitly convert them into java.lang.Integer. However, a somewhat recent change (version 5) does this for you automatically. This is called autoboxing or unboxing, depending on which way the conversion is going. So that's why it works in java.
You don't specify how someInteger is defined, but I assume you are trying to do something like this:
val someObject: Object = "this"
val someInteger = 3
var out = new Formatter(new StringBuilder(), Locale.US)
out.format("%s-%d ", someObject, someInteger);
The problem is that when you say someInteger = 3 in Scala, then the variable is Scala's Int and not Java's int, and Java's Formatter doesn't know what to do with it.
If you change your declaration to use an integer type that Java can understand, then it works just fine. For example:
import java.lang.Integer
val someInteger = new Integer(3)
As for why the ugly asInstanceOf version works? A quick check on the REPL will show you what's happening:
scala> 3.asInstanceOf[java.lang.Object].getClass
res0: java.lang.Class[_ <: java.lang.Object] = class java.lang.Integer
So when you call .asInstanceOf[java.lang.Object] on an Int, Scala gives you back a java.lang.Integer.
But really, you should just rewrite the code in a more Scala-ish way. Andrew McCallum would be happier if you did.
As dhg has said, the scala compiler treats Scala int types as different to Java int types. You could try importing the JavaConversions implicits and see if that helps. I don't quite understand the exact difference (I would have thought it'd treat them the same).
Alternatively you can use the Scala formatting tools:
val someObject: Object = "this"
val someInteger = 3
val out = "%s-%d ".format(someObject, someInteger)
I have this code, which compiles:
new TypeToken<ArrayList<ServerTask>>() {}.getType()
Then I have tried
ArrayList<ServerTask>.class
which does not compile.
I am new to Java programming (came from C#) and I have thought that T.class is an exact equivalent of typeof(T) in C#. Apparently there is something really basic that I do not understand, so my question is what is wrong with ArrayList<ServerTask>.class and do I have no choice, but use new TypeToken<ArrayList<ServerTask>>() {}.getType() instead? Is there a shorter (nicer, saner) form?
Thanks.
Unfortunately (?) Java implements generics using Type Erasure.
This means that there is no construct to get the generic type, and at runtime your ArrayList actually only stores Objects.
To be exact, Generics in Java are a compile-time only construct. They guarantee type-safety at compile time only.
EDIT:
I just noticed this bit of code -
new TypeToken<ArrayList<ServerTask>>() {}.getType()
This is a workaround for the limitations of type erasure. Type information is preserved if you extend a generic class with a specific type. For example:
public interface List<T> {
}
public class StringList implements List<String> {
// The bytecode of this class contains type information.
}
In your example, you are trivially extending the class TypeToken, causing the compiler to generate an anonymous inner class that contains the type information. The implementation of TypeToken.getType() will use reflection to give you this type information.
EDIT2: For a more detailed explanation, have a look at Reflecting Generics.
Your first code sample creates an anonymous subclass of TypeToken complete with concrete generic bindings. The type returned will be an instance of Class. But beware, because
(new TypeToken<ArrayList<ServerTask>>() {}.getType()).getClass(TypeToken.class)
will return false!
In your second code sample, you're trying to do something that Java doesn't support because of how generics are implemented with type erasure. There is no class that represents an ArrayList whose generic parameter is bound...from the compiler's point of view an ArrayList is an ArrayList regardless of the generic type, so the expression doesn't compile.
It's possible that neither piece of code is going to work out quite right. If you need to be playing around classes with generic parameters, you may want to look into gentyref, which I've found to be very helpful in simplifying the API to ask the kinds of questions you're trying to get answers to.
About the ".class" construct, it is not an operator nor an instance member, it is actually a way to tell the language "go and find the Class object for this class name before the dot". Is a way of constructing class literals.
As specified in the JLE, section 15.8.2, the compiler will complain if you try to use it with a parameterized type (among others).
The example given by Bringer128 is considered an anti-pattern called pseudo-typedef antipattern.Here is the alternative:
class TokenUtil{
public static <T> TypeToken<T> newTypeToken(){
return new TypeToken<T>();
}
public static void main(String[] args) {
TypeToken<ArrayList<ServerTask>> typeTok = TokenUtil.newTypeToken();
Type type = typeTok.getType();
}
}
I have a legacy class that the class itself is not a generic but one of its methods return type uses generics:
public class Thing {
public Collection<String> getStuff() { ... }
}
getStuff() uses generics to return a collection of strings. Therefore I can iterate over getStuff() and there's no need to cast the elements to a String:
Thing t = new Thing();
for (String s: t.getStuff()) // valid
{ ... }
However, if I change Thing itself to be a generic but keep everything else the same:
public class Thing<T> {
public Collection<String> getStuff() { ... }
}
and then keep using the non-generic reference to Thing, getStuff() no longer returns Collection<String> and instead returns a non-typed Collection. Thus the client code does not compile:
Thing t = new Thing();
for (String s: t.getStuff()) // compiler complains that Object can't be cast to String
{ ... }
Why is this? What are the workarounds?
My guess is that by using a non-generic reference to a generic class, Java turns off all generics for the entire class. This is pain, because now I've broken my client code by making Thing a generic.
Edit: I'm making Thing generic for another method which is not listed in the above example code. My question is educational as to why the above cannot be done.
Ok, take two, I misunderstood your question.
When you delcare Thing (this is called a raw type) instead of Thing<?> (parameterized type) the Java compiler strips out all generic arguments, even thogh (as in your case) the generic type of the method has nothing to do with the generic type of the class.
From the (excellent) Java Generics FAQ:
Can I use a raw type like any other type?
Methods or constructors of a raw type have the signature that they would have after type erasure.
This seemingly inocuous and unobtrusive sentence describes the behaviour in question. You're using Thing as a raw type so the return type is Collection (not Collection<String>) since this is the type after type erasure.
Confused? Not surprising. Just look at the size of that FAQ. There's probably about three people on earth who nderstand the full implications of Java Generics. Just consider my favourite declaration from the JDK:
Enum<T extends Enum<T>>
(Theres an explanation of that in the FAQ too).
It is failing because of erasure. You can read more about it in these Java Tutorials
I think this is totally normal. In my opinion using Thing t = new Thing(); for generic enabled class is totally a mistake. When compiler see a generic class used as a class without type parameter, it think it must erase all generic types from that class. This is how you can compile old codes without use of generics in new java compilers and compiler let that old codes use generic enabled classes (e.g. java.util.ArrayList) without any problem. (and this is how java not need separated System.Collection.Generic.List and System.Collection.List like C#). You can run Thing t = new Thing(); with adding a simple type parameter on it, Thing<Object> t = new Thing<Object>();, only thing java compiler needs is making sure that you are using java generic consciously. I never can blame Java for its great backward compatibility.
I know I am a bit late :D