The problem of generic arrays (i.e., the impossibility of them) seems to be a recurring theme for me. Below is the relevant code of a HashMap data structure. Obviously, I cannot declare a Bucket[], since generic arrays are impossible. However, I can declare a MapThing.Bucket[]. Am I correct when I assert that this is good practice, since even though MapThing.Bucket[] is a raw type declaration, the actual MapThing.Bucket[] instance is type parameterized by its enclosing instance?
Thanks for any insight!!!
Chris
public class MapThing<K, V> {
private Bucket buckets[];
public static void main(String[] argv) {
MapThing<String, Integer> thing = new MapThing<>();
thing.put("got your number", 8675309);
}
#SuppressWarnings("unchecked")
public MapThing() {
buckets = new MapThing.Bucket[314159];
}
public void put(K key, V value) {
Bucket bucket = new Bucket(key, value);
// Prints typeof bucket key: String, value: Integer
System.out.println("typeof bucket key: "
+ bucket.getKey().getClass().getSimpleName() + ", value: "
+ bucket.getValue().getClass().getSimpleName());
buckets[Math.abs(key.hashCode() % buckets.length)] = bucket;
}
private class Bucket {
private K key;
private V value;
Bucket(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
}
}
Obviously, I cannot declare a Bucket[], since generic arrays are
impossible.
You can ALWAYS declare a variable of any array type. Always. It is perfectly fine to declare variables of Bucket[] or ArrayList<String>[] or whatever.
You cannot use the array creation expression (i.e. new X[...]) with a parameterized type (i.e. if X is Something<SomethingElse> where SomethingElse is anything except ?). You can use array creation expression with a raw type (i.e. new X[...] where X is a raw type), e.g. new ArrayList[10].
Therefore, if Bucket were a raw type, then new Bucket[10] would be perfectly fine. The thing is, Bucket is not a raw type. Bucket is a non-static inner class inside a generic outer class. That means it is within the scope of the type parameters of its outer class. In other words, if you write the unqualified type Bucket inside MapThing, it implicitly means MapThing<K,V>.Bucket, which is a parameterized type.
To get the raw type, you need to explicitly qualify it with the outer class, as in MapThing.Bucket. So new MapThing.Bucket[10] will work.
Alternately, if you don't want to use raw types, you can parameterize it with all wildcards: new MapThing<?,?>.Bucket[10].
Related
Given the following class:
public class TestMap<K,V> {
private HashMap<K,V> map;
public void put(K k, V v) {
map.put(k, v);
}
public V get(K k) {
return map.get(k);
}
}
and this function:
static<T extends Object> String getObj(TestMap<T, String> m, String e) {
return m.get(e);
}
Why does "get" show this error:
The method get(T) in the type MyHashMap<T,String> is not applicable for the arguments (String)
When getObj states T extends Object, and the map has been initialized with TestMap<T, String> m, why can't String be used as parameter? I cant wrap my head around why this doesnt work, as String is a subtype of Object ?
I tried extending T from a custom superclass and using a subclass instead of String.
get() requires as an argument a key, which is of type T, not String.
So either you need to change e to type T or change the type of the Map, e.g., to TestMap<String, T>.
Generics describe what an Object is, List<String> strings is a list of Strings. That gives us some convenience, we don't have to cast. String s = strings.get(0); and we get some compile-time protection. Integer i = 1; then strings.add(i); fails to compile.
The error you are getting is a compile time protection. The key you're providing is an Object, so it might be the correct type. In the case of a map, "why not check?" It is just going to hashcode and check for equality which is ok. In the case of a List though, strings.add((Object)i); needs to fail.
If the doesn't fail, then later something might call. for(String s: strings) and get a class cast exception.
To fix this you can change you V get(K k) method to a V get(Object k) the same as map uses. Your get method requires type K a map normally has a get method with a Object
As mentioned "T extends Object" is the same as just "T". You use the extends when you want to put a lower bound on something. public <T extends Number> int sum(List<T> numbers). In this case "T" can be any class that extends numbers. We can do Number n = numbers.get(0); because we know it is at least a number. But we could not do numbers.add(n); because while T is at least a number, it could be something else like an Integer, Double, Number, BigDecimal etc.
class Matrix<T>{
private List<Attribute<T>> attributes;
public Matrix(T type){
attributes = new ArrayList<Attribute<T>>();
attributes.add(new Attribute<T>(type));
}
}
I feel like in the constructor, these two lines should be use a specific type, not the generic T:
attributes = new ArrayList<Attribute<T>>();
attributes.add(new Attribute<T>(type));
But the compiler doesn't complain. So this is the right way to define this class?
Yes, thats the right way. The only thing where you might be wrong is that your Parameter in the constructor should not be namend type, but value. The Type is T.
If you need to, you can say that your Generic has to a childtype of something else. Let's say we have a class which holds an Exception. We could just make a Membervariable of Type Exception. But when getting the Exception from inside this Object, we don't want to cast our Exception to a more specific one.
So we use a Generic which must be a childtype of Exception:
public class SomeClass<T extends Exception>
{
private final T value;
public SomeClass(T value)
{
this.value = value;
}
public T getValue()
{
return this.value;
}
}
Now we can do stuff like this:
SomeClass<ArrayIndexOutOfBoundsException> obj = new SomeClass<>(new ArrayIndexOutOfBoundsException());
ArrayIndexOutOfBoundsException exc = obj.getValue(); // no cast from Exception to ArrayIndexOutOfBoundsException needed
I feel like in the constructor, these two lines should be use a specific type, not the generic T
No, because your class Matrix is generic on the type parameter T. This means that it encapsulates a list of attributes of the type T, namely: List<Attribute<T>>.
If you use it with Integer:
Matrix<Integer> integerMatrix = new Matrix<>(1);
Then 1 would be inside the first attribute of the list.
However, if you declare another matrix with String:
Matrix<String> stringMatrix = new Matrix<>("hello");
Then your matrix will hold attributes that encapsulate String values.
Is it possible to write an equivalent code in Java for the following swift code? In fact, I want to know if it's possible to have a case of functions inside Java's enum (X, Y in MyEnum)
enum MyEnum{
case X((Int) -> String)
case Y((Double) -> Int)
}
No, you can't; at least, not if you want the differing types to be available when you use the enum. All enum values have to have the same type.
When you want "enum" values to have heterogenous types, you could use a class with static final fields:
final class MyHeterogeneousEnum {
private MyHeterogeneousEnum() {} // Not instantiable.
static final Function<Integer, String> X = ...;
static final Function<Double, Integer> Y = ...;
}
which allows you to use the values with their full type information:
String s = MyHeterogeneousEnum.X.apply(123);
Integer i = MyHeterogeneousEnum.Y.apply(999.0);
Of course, you don't have useful methods like name(), or values() to iterate over the constants in this class, nor is it inherently serializable. You can make implement these yourself - but for values() you have to use wildcards in the return type, in order that all values can be returned:
static Iterable<Function<?, ?>> values() {
return Collections.unmodifiableList(Arrays.asList(X, Y));
}
However, note that a Function with a wildcard input type parameter is pretty much useless: you can't actually pass anything into it (other than null); so the values() method has limited utility.
It is possible (technically), but it might not be that useful, as creating a simple class, that consumes a Function instance.
As you might already know, in Java, the enums represent one or more constants of the same type, which could have their own properties - this include java.util.Function instances. However, these Function instances cannot be passed dynamically at Runtime, but should be rather set at compile time, so that the constant is created.
Of course, you could make each enum constant have a different typed Function, by just creating the enum's constructor Generic:
enum MyEnum {
X((String x) -> "Hello"), Y((Double d) -> 1);
Function<?, ?> function;
MyEnum(Function<?, ?> function) {
this.function = function;
}
}
This, however, is not quite useful (although it compiles just fine). The Function in X doesn't use it's String parameter and returns a fixed value. So does the one in Y.
I'd rather introduce two separate instances of the same class:
class Instance<T, U> {
private Function<T, U> function;
public Instance(Function<T, U> function) {
this.function = function;
}
}
This will allow you to dynamically pass a Function instance, instead of setting it at compile-time.
Yes for sure you can, in java enums can be more that just constants... every one of it values can be an anonymous class (take a look to TimeUnit.class for example)
now, you can do somthing like:
interface IFunction {
double getY(double x);
}
enum Function implements IFunction {
LINE {
#Override
public double getY(double x) {
return x;
}
},
SINE {
#Override
public double getY(double x) {
return Math.sin(x);
}
}
}
and then the implementation
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(Function.LINE.getY(i));
System.out.println(Function.SINE.getY(i));
}
}
I'm implementing a weighted probability algorithm, so I created a generic Pair class. Since the probability is calculated using numbers, the value of Pair would always be an Integer, but I wanted it to work the way where the key could be any Object. This is what I got:
class Pair<K, Integer> {
public K k;
public java.lang.Integer v;
public Pair(K k, java.lang.Integer v) {
this.k = k;
this.v = v;
}
// getters and other stuff
}
It works fine, but I find it weird that no matter what I type instead of the Integer part in the first line, it works the same. Am I missing something? Is there a better way to do that?
class Pair<K, Integer>
is equivalent to
class Pair<K, V>
where the name of the second generic parameter would happen to be Integer instead of V (and thus hiding the type java.lang.Integer, which forces you to use java.lang.Integer instead of just Integer in the code, to avoid a conflict).
Your class should only have one generic parameter:
class Pair<K>
You use generics when you may accept any type.
But since you know that type to be Integer, you do not need to make it generic.
The new version with one generic type argument will look like this:
public class Pair<T> {
public T t;
public int v;
public Pair(T t, int v) {
this.t = t;
this.v = v;
}
// ...
}
It is good practice, when you have just one generic type argument, to name it with the "T" letter.
Also, you can now use int instead of Integer.
The way you use it, Integer is just a type variable, same as K.
If you don't need the type of the second value of the pair to be a parameter, then don't declare it as type parameter, but just use Integer in the code:
class IntPair<K> {
private K first;
private Integer second;
public Integer someIntegerSpecificFunction() {
// do stuff to internalPair.second
}
K getFirst() {
return first;
}
Integer getSecond() {
return second;
}
}
I am currently new to working with Java. So far I have been able to easily use the basic such as Classes, Functions, Arrays etc from my knowledge of JavaScript and PHP.
However, what I have never seen before is this: <>. Inside of that is a variable of some type. Because I don't know what it is called, I can't find any answers.
I've seen them like this:
List<String> myList = new ArrayList<String>();
But also like:
public static <T> boolean contains( final T[] array, final T v ) {
for ( final T e : array )
if ( e == v || v != null && v.equals( e ) )
return true;
return false;
}
What does the <String> mean?
In the function, I was also wondering what is specifically special about the T?
This is for a Generic type
What it allows you to do is to pass through a type, and make it useful for multiple object types
So List is a generic collection, and it allows you to make a list of any object. Making List<String> will make the object be a list of Strings. Or you could use List<MyClassType> and it would make a list of objects of your class
That defines the Type of the objects a collection can hold
so when you write List<String> myList = new ArrayList<String>();, it means
Create an arrayList that can hold the String objects.
SomeParameterizedClass{
T someValue;
}
means that you can pass your type to the class e.g. SomeParameterizedClass<String> so that someValue becomes of type String
When you write List<T> list = new ArrayList<T>();, here T can be any type.
With java 7 you can simply say List<String> list = new ArrayList<>();. It has the same meaning.
In java 7 <> is called as diamond operator
You will find < > in the following cases, the T is a "parameter type" in plain English that means you could "substitute" that T by any other non-primitive type (like String or Integer):
When you are declaring a parameterized Type:
class MyParameterizedClass<T> {
public T myValue;
}
When you are declaring variables of your parameterized type:
MyParameterizedClass<String> myStringParam;
MyParameterizedClass<Integer> myIntegerParam;
When you are using constructors of parameterized types:
MyParameterizedClass<String> myStringParam = new MyParameterizedClass<String>();
MyParameterizedClass<Integer> myIntegerParam = new MyParameterizedClass<Integer>();
myStringParam.myValue = "Hello world";
myIntegerParam.myValue = 5;
When you declare a generic method:
public <T> T updateMyValue(T myValue) {
this.myValue = myValue
}
What you have observed is partially correct! In Java, inside <> should be 'Object' type or any subclass type of 'Object'.
When you declare myList as below:
List<String> myList = new ArrayList<String>(), it ensures the declared and initialized myList has elements of only String type. This is called type declarations.
public static <T> boolean contains( final T[] array, final T v ) { }, is a generic method declaration which implies that the passed two parameters should be of same object type, 1st parameter an array, 2nd parameter an object. And the method return type also should be same type.
Refer Java docs for more examples on Generics. http://docs.oracle.com/javase/tutorial/extra/generics/methods.html