DeepEquals.deepEquals(refObject, ref) - java

When I use deepEquals of two empty list it return true even that two lists are of different types. I know that the lists only is of different types while compiling and not runtime.
But is there opportunity of annotates the field or something familiar?
So this what I want:
List<Foo> fooList = []
List<Boo> booList = []
DeepEquals.deepEquals(fooList, booList) //I want it to return false, as the list differs on type
Doing runtime the list appears as ArrayList without typing

There is no solution for this right now in Java or Groovy.
You are seeing Java type erasure at work. It was a decision made for things to work that way when generics were added to Java back with Java 1.5.
Basically the compiled class is List.
And each field is an instance of that type and are effectively both List<Object> at runtime.
The information abut the parameter type is simply not available any longer.
A fuller explanation of type erasure can be found here:
Java generics type erasure: when and what happens?
Other runtimes such as .NET do have reified types, meaning List<Foo> and List<Bar> are two separate types. Both approaches have their pros and cons.
There has been some discussion and work for the JVM to have something similar in the future. Some of the talks at the JVM Language Summit (JVMLS) show that John Rose and others have been considering template classes and type species to try and solve this problem. So List would be the class but there could be a species for each of List<Foo> and List<Bar>. But AFAIK that is several years away, if it ever arrives.

Related

How do I get the class of a parameterized type in Java without instantiating it? [duplicate]

If I am creating a java class to be generic, such as:
public class Foo<T>
How can one determine internally to that class, what 'T' ended up being?
public ???? Bar()
{
//if its type 1
// do this
//if its type 2
// do this
//if its type 3
// do this
//if its type 4
// do this
}
I've poked around the Java API and played with the Reflection stuff, instanceof, getClass, .class, etc, but I can't seem to make heads or tails of them. I feel like I'm close and just need to combine a number of calls, but keep coming up short.
To be more specific, I am attempting to determine whether the class was instantiated with one of 3 possible types.
I've used a similar solution to what he explains here for a few projects and found it pretty useful.
http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/
The jist of it is using the following:
public Class returnedClass() {
ParameterizedType parameterizedType = (ParameterizedType)getClass()
.getGenericSuperclass();
return (Class) parameterizedType.getActualTypeArguments()[0];
}
In contrast to .NET Java generics are implemented by a technique called "type erasure".
What this means is that the compiler will use the type information when generating the class files, but not transfer this information to the byte code. If you look at the compiled classes with javap or similar tools, you will find that a List<String> is a simple List (of Object) in the class file, just as it was in pre-Java-5 code.
Code accessing the generic List will be "rewritten" by the compiler to include the casts you would have to write yourself in earlier versions. In effect the following two code fragments are identical from a byte code perspective once the compiler is done with them:
Java 5:
List<String> stringList = new ArrayList<String>();
stringList.add("Hello World");
String hw = stringList.get(0);
Java 1.4 and before:
List stringList = new ArrayList();
stringList.add("Hello World");
String hw = (String)stringList.get(0);
When reading values from a generic class in Java 5 the necessary cast to the declared type parameter is automatically inserted. When inserting, the compiler will check the value you try to put in and abort with an error if it is not a String.
The whole thing was done to keep old libraries and new generified code interoperable without any need to recompile the existing libs. This is a major advantage over the .NET way where generic classes and non-generic ones live side-by-side but cannot be interchanged freely.
Both approaches have their pros and cons, but that's the way it is in Java.
To get back to your original question: You will not be able to get at the type information at runtime, because it simply is not there anymore, once the compiler has done its job. This is surely limiting in some ways and there are some cranky ways around it which are usually based on storing a class-instance somewhere, but this is not a standard feature.
Because of type erasure, there is no way to do this directly. What you could do, though, is pass a Class<T> into the constructor and hold onto it inside your class. Then you can check it against the three possible Class types that you allow.
However, if there are only three possible types, you might want to consider refactoring into an enum instead.
The Problem is that most of the Generic stuff will disappear during compilation.
One common solution is to save the type during the creation of the Object.
For a short introduction in the Type Erasure behaviour of java read this page
If you know a few specific types that are meaningful, you should create subclasses of your generic type with the implementation.
So
public class Foo<T>
public ???? Bar()
{
//else condition goes here
}
And then
public class DateFoo extends Foo<Date>
public ???? Bar()
{
//Whatever you would have put in if(T == Date) would go here.
}
The whole point of a generic class is that you dont need to know the type that is being used....
It looks like what you want is in fact not a Generic class, but an interface with a number of different implementations. But maybe it would become clearer if you stated your actual, concrete goal.
I agree with Visage. Generics is for compile-time validation, not runtime dynamic typing. Sounds like what you need is really just the factory pattern. But if your "do this" isn't instantiation, then a simple Enum will probably work just as well. Like what Michael said, if you have a slightly more concrete example, you'll get better answers.

Why does erasure complicate implementing function types?

I read from an interview with Neal Gafter:
"For example, adding function types to the programming language is much more difficult with Erasure as part of Generics."
EDIT:
Another place where I've met similar statement was in Brian Goetz's message in Lambda Dev mailing list, where he says that lambdas are easier to handle when they are just anonymous classes with syntactic sugar:
But my objection to function types was not that I don't like function types -- I love function types -- but that function types fought badly with an existing aspect of the Java type system, erasure. Erased function types are the worst of both worlds. So we removed this from the design.
Can anyone explain these statements? Why would I need runtime type information with lambdas?
The way I understand it, is that they decided that thanks to erasure it would be messy to go the way of 'function types', e.g. delegates in C# and they only could use lambda expressions, which is just a simplification of single abstract method class syntax.
Delegates in C#:
public delegate void DoSomethingDelegate(Object param1, Object param2);
...
//now assign some method to the function type variable (delegate)
DoSomethingDelegate f = DoSomething;
f(new Object(), new Object());
(another sample here
http://geekswithblogs.net/joycsharp/archive/2008/02/15/simple-c-delegate-sample.aspx)
One argument they put forward in Project Lambda docs:
Generic types are erased, which would expose additional places where
developers are exposed to erasure. For example, it would not be
possible to overload methods m(T->U) and m(X->Y), which would be
confusing.
section 2 in:
http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-3.html
(The final lambda expressions syntax will be a bit different from the above document:
http://mail.openjdk.java.net/pipermail/lambda-dev/2011-September/003936.html)
(x, y) => { System.out.printf("%d + %d = %d%n", x, y, x+y); }
All in all, my best understanding is that only a part of syntax stuff that could, actually will be used.
What Neal Gafter most likely meant was that not being able to use delegates will make standard APIs more difficult to adjust to functional style, rather than that javac/JVM update would be more difficult to be done.
If someone understands this better than me, I will be happy to read his account.
Goetz expands on the reasoning in State of the Lambda 4th ed.:
An alternative (or complementary) approach to function types,
suggested by some early proposals, would have been to introduce a new,
structural function type. A type like "function from a String and an
Object to an int" might be expressed as (String,Object)->int. This
idea was considered and rejected, at least for now, due to several
disadvantages:
It would add complexity to the type system and further mix structural and nominal types.
It would lead to a divergence of library styles—some libraries would continue to use callback interfaces, while others would use structural
function types.
The syntax could be unweildy, especially when checked exceptions were included.
It is unlikely that there would be a runtime representation for each distinct function type, meaning developers would be further exposed to
and limited by erasure. For example, it would not be possible (perhaps
surprisingly) to overload methods m(T->U) and m(X->Y).
So, we have instead chosen to take the path of "use what you
know"—since existing libraries use functional interfaces extensively,
we codify and leverage this pattern.
To illustrate, here are some of the functional interfaces in Java SE 7
that are well-suited for being used with the new language features;
the examples that follow illustrate the use of a few of them.
java.lang.Runnable
java.util.concurrent.Callable
java.util.Comparator
java.beans.PropertyChangeListener
java.awt.event.ActionListener
javax.swing.event.ChangeListener
...
Note that erasure is just one of the considerations. In general, the Java lambda approach goes in a different direction from Scala, not just on the typed question. It's very Java-centric.
Maybe because what you'd really want would be a type Function<R, P...>, which is parameterised with a return type and some sequence of parameter types. But because of erasure, you can't have a construct like P..., because it could only turn into Object[], which is too loose to be much use at runtime.
This is pure speculation. I am not a type theorist; i haven't even played one on TV.
I think what he means in that statement is that at runtime Java cannot tell the difference between these two function definitions:
void doIt(List<String> strings) {...}
void doIt(List<Integer> ints) {...}
Because at compile time, the information about what type of data the List contains is erased, so the runtime environment wouldn't be able to determine which function you wanted to call.
Trying to compile both of these methods in the same class will throw the following exception:
doIt(List<String>) clashes with doIt(List<Integer); both methods have the same erasure

reason generics were introduced in java 5

Can someone explain what were the reasons generics were introduced in Java?
As far as I understand they were introduced so that you don't accidentally add the wrong type of object to a collection.
I kind of like the generics for collection but can't see why they were added for other classes too. I have seen some generic classes that make your head hurt and your eyes bleed.
So what are all the reasons generics were introduced (mainly for non collections)?
TIA!
Essentially type safety and convenience.
Java implements its generics by a mechanism known as type erasure which effectively replaces the generic definition with a non-generic definition at compile time. The reason this was done was to maintain API compatability between 1.4 and 1.5 - the collections API may well have been updated but if you accessed it in a non-generic way in 1.5 it would work the same.
The difference was that if you intended a collection to only contain particular types of objects you could explictly encode that requirement in your APIs and avoid issues such as receiving a list with the wrong type of objects in it - and also the need to have to explictly cast those objects making your code simpler to read and less error prone.
You would use the generics for essentially the same reasons as when they are used with collections - when you need to say that an object is a composite of other objects, but that there may be a range of types possible for that composition and that once bound the addition of these new objects implies a new composite type disimilar to other similar composites. That is to say a list of strings is similar in type to a list of integers but they are no longer compatible with each other.
One example of this is in the Future where you are waiting for an asynchronous result. The Future class encapsulates the concept of the asynchronous result, but the specific type of Future such as Future<String> futher specifies what type of result you can expect - and makes it distinct from Future<Integer>.
The Java Collection Framework is nothing special from a Java perspective, so there's no reason or need to add a new language feature to this framework only.
Look at generics from a user perspective: Now if you have a collection you know what kind of objects are in it. That's a great advantage. Just compare the following snippets, without and with generics:
With Java 1.5+
List<Animal> zoo = new ArrayList<Animal>();
for(Animal animal:zoo) {
feed(animal);
}
Before Java 1.5-
List zoo = new ArrayList();
for (int i = 0; i < zoo.size(); i++) {
if (!(zoo.get(i) instanceof Animal)) {
continue;
} else {
Animal animal = (Animal) zoo.get(i);
feed(animal);
}
}
From users perspective, it's more the old style that hurts the eye.
They were added because the only way to make a truly generic placeholder in the original Java was to have a field of type Object. This can take any object.
Unfortunately when you NEED it again it is of type Object which doesn't hold any interesting methods, so you need to cast it to the type you happen to know it has. These runtime casts were a frequent source of error and - by nature - happened at runtime.
Generics move this to the compiler, and cause a LOT less ClassCastExceptions which improve quality. The actual syntax is a bit verbose - here the C# keyword 'var' would help a lot - but the bit of extra labor gives a lot of payoff.
I believe you have to had programmed in a strongly typed language like Haskell to know what is possible, and why it is desirable.
Generics afford the programmer some type safety. The most obvious use is to prevent a user inadvertantly passing the wrong type into a function. They can also be used to avoid a lot of noisy casting.
Here is a non collection example that would benefit from a generic. If we have lots of views which are associated with a model, we might define an interface to represent a view. The interface might have a getModel() method:
public interface View {
Model getModel();
}
Anyone that calls the method has to cast the result which is a pain:
MyView view = new MyView();
MyModel model = (MyModel) view.getModel();
So instead we specify interface using as generic:
public interface View<M extends Model> {
M getModel();
}
A concrete class called MyView
class MyView implements View<MyModel> {
MyModel getModel();
}
Then the client code is a bit cleaner:
MyView view = new MyView();
MyModel model = view.getModel();
With careful crafting generics can make code a lot more readable. However generic type info doesn't get compiled into the class file so there is still potential for abuse at runtime.
Anyplace where you want to do generic programming ;-)
It is, you don't mind (too much) about the type of some object, but want to restrict its type to function properly.
Imaging pipe&filters. Imagine each pipe has a specific output. One outputs bytes, other strings, and other numbers. It would be nice each pipe has its specific type and you could only hook a pipe of an X output to a pipe of an X input.
Byte -> Filter -> String -> Filter -> Integer
So your first Filter will be Filter<Byte, String> and its hookOutputPipe will receive a Pipe<String>.
Maybe your eyes bleed with over parametrized types, but in some situations it's a pretty good allied for an API developer. If you start to use them in appropiate situations you'll feel the usefulness of them.
One example from real world: event types and handler types in GWT.
Two main objectives of Generics concepts are
1. To provide type safety to the collection so that they can hold only particular type of object
2.To resolve type casting problems
ArrayList<String> ob=new ArrayList<String>();
ob.add("shail");
ob.add("ball");
ob.add(10); //compile time error
At the time of retrival does not require type casting
String s1=ob.get(0);
JDK 5.0 introduces several new extensions to the Java programming language, one of these is the introduction of Generics.
Generics provides the abstraction over types. Here is a typical usage of that sort:
List l1 = new LinkedList(); // 1
l1.add(new Integer(10)); // 2
Integer x = (Integer) l1.iterator().next(); // 3
The cast on line 3 is slightly annoying. Typically, the programmer knows what kind of data has been placed into a particular list. However, the cast is essential. To ensure the assignment to a variable of type Integer is type safe, the cast is required.
Of course, the cast not only introduces clutter. It also introduces the possibility of a run time error, since the programmer may be mistaken.
What if programmers could mark a list as being restricted to contain a particular data type? This is the core idea behind generics.
Here is a example of the above given program using generics:
List <Integer> l1 = new LinkedList <Integer>(); // 1
l1.add(new Integer(10)); // 2
Integer x = l1.iterator().next(); // 3
Notice the type declaration for the variable l1. It specifies that this is not just an arbitrary List, but a List of Integer, written List. We say that List is a generic interface that takes a type parameter–in this case, Integer. We also specify a type parameter when creating the list object.
enter link description here
Generics are indeed particularly useful in collection classes, but their usefulness is not limited to that. I can't imagine how the generic capability could have been made available to collection classes and yet not be made generally available - generics are a fundamental language feature not a specific patch for collections. Would you want the compiler to have logic like:
if this is a collection class
allow generics
and how could the compiler spot that it has a collection class - after I can write my own collections.
Like many sharp tools generics can be misapplied and overused, that doesn't make the tool itself a bad thing.
Lets say, we want to write a method to find the maximum of two comparable objects, similar to Math.max():
public static <T extends Comparable<T>> T max(T arg0, T arg1) {
return arg0.compareTo(arg1) > 0 ? arg0 : arg1;
}
Now you can call the method like this,
int maxNum = max(5 ,3);
String maxString = max("AAA", "BBB");
File maxFile = max(new File("path/to/file1"), new File("path/to/file2"));
Try defining this functionality without generics. Here the return type is inferred and you dont need any type casting at all. Further the type is checked at compile time rather than resulting in ClassCastException at runtime.
Elimination of explicit cast
Stronger type checking at compile time
Elimination of explicit cast
Without generics:
List a = new LinkedList();
a.add(new Integer(5));
Integer i = (Integer)a.get(0); //Manual type conversion
With generics:
List<Integer> a = new LinkedList();
a.add(new Integer(5));
Integer i = a.get(0);
This restricts the data types the list can contain at first place.
Stronger type checking at compile time
Without generics:
List a = new LinkedList();
a.add("asia");
Integer i = (Integer)a.get(0); //compiles successfully
The above code compiles successfully but throws ClassCastException at runtime.
With generics:
List<String> a = new LinkedList();
a.add("asia");
Integer i = a.get(0); //compile time error
The above code will break at compilation itself and save us from runtime error.
Java Generics is only a compile time concept.During run-time all type
information is erased and this is called Type erasure.
Essentially to prevent bugs, by detecting type errors at compile time.
Generics allow you to follow the DRY principle while maintaining type safety.
Quoting Oracle's Java documentation on Generics:
Generics add stability to your code by making more of your bugs
detectable at compile time.
And the Introduction of the Generics tutorial by Gilad Bracha:
The net effect, especially in large programs, is improved readability
and robustness.
Not only collections can make use of generics, you can easily think of decorators, proxies, and much more cases.
From JavaDocs
In a nutshell, generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. Much like the more familiar formal parameters used in method declarations, type parameters provide a way for you to re-use the same code with different inputs. The difference is that the inputs to formal parameters are values, while the inputs to type parameters are types.
Code that uses generics has many benefits over non-generic code:
Stronger type checks at compile time. A Java compiler applies strong
type checking to generic code and issues errors if the code violates
type safety. Fixing compile-time errors is easier than fixing
runtime errors, which can be difficult to find.
Elimination of casts. The following code snippet without generics
requires casting:
List list = new ArrayList(); list.add("hello");
String s = (String) list.get(0);
When re-written to use generics,
the code does not require casting:
List<String> list = new
ArrayList<String>(); list.add("hello"); String s = list.get(0);
Enabling programmers to implement generic algorithms. By using
generics, programmers can implement generic algorithms that work on
collections of different types, can be customized, and are type safe
and easier to read.

What is truly wrong with Java generics? [duplicate]

I've occasionally heard that with generics, Java didn't get it right. (nearest reference, here)
Pardon my inexperience, but what would have made them better?
Bad:
Type information is lost at compile time, so at execution time you can't tell what type it's "meant" to be
Can't be used for value types (this is a biggie - in .NET a List<byte> really is backed by a byte[] for example, and no boxing is required)
Syntax for calling generic methods sucks (IMO)
Syntax for constraints can get confusing
Wildcarding is generally confusing
Various restrictions due to the above - casting etc
Good:
Wildcarding allows covariance/contravariance to be specified at calling side, which is very neat in many situations
It's better than nothing!
The biggest problem is that Java generics are a compile-time only thing, and you can subvert it at run-time. C# is praised because it does more run-time checking. There is some really good discussion in this post, and it links to other discussions.
The main problem is that Java doesn't actually have generics at runtime. It's a compile time feature.
When you create a generic class in Java they use a method called "Type Erasure" to actually remove all of the generic types from the class and essentially replace them with Object. The mile high version of generics is that the compiler simply inserts casts to the specified generic type whenever it appears in the method body.
This has a lot of downsides. One of the biggest, IMHO, is that you can't use reflection to inspect a generic type. Types are not actually generic in the byte code and hence can't be inspected as generics.
Great overview of the differences here: http://www.jprl.com/Blog/archive/development/2007/Aug-31.html
Runtime implementation (ie not type erasure);
The ability to use primitive types (this is related to (1));
While the wildcarding is useful the syntax and knowing when to use it is something that stumps a lot of people. and
No performance improvement (because of (1); Java generics are syntactic sugar for castingi Objects).
(1) leads to some very strange behaviour. The best example I can think of is. Assume:
public class MyClass<T> {
T getStuff() { ... }
List<String> getOtherStuff() { ... }
}
then declare two variables:
MyClass<T> m1 = ...
MyClass m2 = ...
Now call getOtherStuff():
List<String> list1 = m1.getOtherStuff();
List<String> list2 = m2.getOtherStuff();
The second has its generic type argument stripped off by the compiler because it is a raw type (meaning the parameterized type isn't supplied) even though it has nothing to do with the parameterized type.
I'll also mention my favourite declaration from the JDK:
public class Enum<T extends Enum<T>>
Apart from wildcarding (which is a mixed bag) I just think the .Net generics are better.
I'm going to throw out a really controversial opinion. Generics complicate the language and complicate the code. For example, let's say that I have a map that maps a string to a list of strings. In the old days, I could declare this simply as
Map someMap;
Now, I have to declare it as
Map<String, List<String>> someMap;
And every time I pass it into some method, I have to repeat that big long declaration all over again. In my opinion, all that extra typing distracts the developer and takes him out of "the zone". Also, when code is filled with lots of cruft, sometimes it's hard to come back to it later and quickly sift through all the cruft to find the important logic.
Java already has a bad reputation for being one of the most verbose languages in common use, and generics just add to that problem.
And what do you really buy for all that extra verbosity? How many times have you really had problems where someone put an Integer into a collection that's supposed to hold Strings, or where someone tried to pull a String out of a collection of Integers? In my 10 years of experience working at building commercial Java applications, this has just never been a big source of errors. So, I'm not really sure what you're getting for the extra verbosity. It really just strikes me as extra bureaucratic baggage.
Now I'm going to get really controversial. What I see as the biggest problem with collections in Java 1.4 is the necessity to typecast everywhere. I view those typecasts as extra, verbose cruft that have many of the same problems as generics. So, for example, I can't just do
List someList = someMap.get("some key");
I have to do
List someList = (List) someMap.get("some key");
The reason, of course, is that get() returns an Object which is a supertype of List. So the assignment can't be made without a typecast. Again, think about how much that rule really buys you. From my experience, not much.
I think Java would have been way better off if 1) it had not added generics but 2) instead had allowed implicit casting from a supertype to a subtype. Let incorrect casts be caught at runtime. Then I could have had the simplicity of defining
Map someMap;
and later doing
List someList = someMap.get("some key");
all the cruft would be gone, and I really don't think I'd be introducing a big new source of bugs into my code.
Another side effect of them being compile-time and not run time is that you can't call the constructor of the generic type. So you can't use them to implement a generic factory...
public class MyClass {
public T getStuff() {
return new T();
}
}
--jeffk++
Ignoring the whole type erasure mess, generics as specified just don't work.
This compiles:
List<Integer> x = Collections.emptyList();
But this is a syntax error:
foo(Collections.emptyList());
Where foo is defined as:
void foo(List<Integer> x) { /* method body not important */ }
So whether an expression type checks depends on whether it is being assigned to a local variable or an actual parameter of a method call. How crazy is that?
Java generics are checked for correctness at compile time and then all type information is removed (the process is called type erasure. Thus, generic List<Integer> will be reduced to its raw type, non-generic List, which can contain objects of arbitrary class.
This results in being able to insert arbitrary objects to the list at runtime, as well as it's now impossible to tell what types were used as generic parameters. The latter in turn results in
ArrayList<Integer> li = new ArrayList<Integer>();
ArrayList<Float> lf = new ArrayList<Float>();
if(li.getClass() == lf.getClass()) // evaluates to true
System.out.println("Equal");
Java generics are compile-time only and are compiled into non-generic code. In C#, the actual compiled MSIL is generic. This has huge implications for performance because Java still casts during runtime. See here for more.
The introduction of generics into Java was a difficult task because the architects were trying to balance functionality, ease of use, and backward compatibility with legacy code. Quite expectedly, compromises had to be made.
There are some who also feel that Java's implementation of generics increased the complexity of the language to an unacceptable level (see Ken Arnold's "Generics Considered Harmful"). Angelika Langer's Generics FAQs gives a pretty good idea as to how complicated things can become.
I wish this was a wiki so I could add to other people... but...
Problems:
Type Erasure (no runtime availability)
No support for primative types
Incompatability with Annotations (they were both added in 1.5 I'm still not sure why annotations don't allow generics aside from rushing the features)
Incompatability with Arrays. (Sometimes I really want to do somthing like Class<? extends MyObject>[], but I'm not allowed)
Wierd wildcard syntax and behavior
The fact that generic support is inconsistant across Java classes. They added it to most of the collections methods, but every once in a while, you run into an instance where its not there.
Java doesn't enforce Generics at run time, only at compile time.
This means that you can do interesting things like adding the wrong types to generic Collections.
If you listen to Java Posse #279 - Interview with Joe Darcy and Alex Buckley, they talk about this issue. That also links to a Neal Gafter blog post titled Reified Generics for Java that says:
Many people are unsatisfied with the
restrictions caused by the way
generics are implemented in Java.
Specifically, they are unhappy that
generic type parameters are not
reified: they are not available at
runtime. Generics are implemented
using erasure, in which generic type
parameters are simply removed at
runtime.
That blog post, references an older entry, Puzzling Through Erasure: answer section, that stressed the point about migration compatibility in the requirements.
The goal was to provide backwards
compatibility of both source and
object code, and also migration
compatibility.

Java Generic Class - Determine Type

If I am creating a java class to be generic, such as:
public class Foo<T>
How can one determine internally to that class, what 'T' ended up being?
public ???? Bar()
{
//if its type 1
// do this
//if its type 2
// do this
//if its type 3
// do this
//if its type 4
// do this
}
I've poked around the Java API and played with the Reflection stuff, instanceof, getClass, .class, etc, but I can't seem to make heads or tails of them. I feel like I'm close and just need to combine a number of calls, but keep coming up short.
To be more specific, I am attempting to determine whether the class was instantiated with one of 3 possible types.
I've used a similar solution to what he explains here for a few projects and found it pretty useful.
http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/
The jist of it is using the following:
public Class returnedClass() {
ParameterizedType parameterizedType = (ParameterizedType)getClass()
.getGenericSuperclass();
return (Class) parameterizedType.getActualTypeArguments()[0];
}
In contrast to .NET Java generics are implemented by a technique called "type erasure".
What this means is that the compiler will use the type information when generating the class files, but not transfer this information to the byte code. If you look at the compiled classes with javap or similar tools, you will find that a List<String> is a simple List (of Object) in the class file, just as it was in pre-Java-5 code.
Code accessing the generic List will be "rewritten" by the compiler to include the casts you would have to write yourself in earlier versions. In effect the following two code fragments are identical from a byte code perspective once the compiler is done with them:
Java 5:
List<String> stringList = new ArrayList<String>();
stringList.add("Hello World");
String hw = stringList.get(0);
Java 1.4 and before:
List stringList = new ArrayList();
stringList.add("Hello World");
String hw = (String)stringList.get(0);
When reading values from a generic class in Java 5 the necessary cast to the declared type parameter is automatically inserted. When inserting, the compiler will check the value you try to put in and abort with an error if it is not a String.
The whole thing was done to keep old libraries and new generified code interoperable without any need to recompile the existing libs. This is a major advantage over the .NET way where generic classes and non-generic ones live side-by-side but cannot be interchanged freely.
Both approaches have their pros and cons, but that's the way it is in Java.
To get back to your original question: You will not be able to get at the type information at runtime, because it simply is not there anymore, once the compiler has done its job. This is surely limiting in some ways and there are some cranky ways around it which are usually based on storing a class-instance somewhere, but this is not a standard feature.
Because of type erasure, there is no way to do this directly. What you could do, though, is pass a Class<T> into the constructor and hold onto it inside your class. Then you can check it against the three possible Class types that you allow.
However, if there are only three possible types, you might want to consider refactoring into an enum instead.
The Problem is that most of the Generic stuff will disappear during compilation.
One common solution is to save the type during the creation of the Object.
For a short introduction in the Type Erasure behaviour of java read this page
If you know a few specific types that are meaningful, you should create subclasses of your generic type with the implementation.
So
public class Foo<T>
public ???? Bar()
{
//else condition goes here
}
And then
public class DateFoo extends Foo<Date>
public ???? Bar()
{
//Whatever you would have put in if(T == Date) would go here.
}
The whole point of a generic class is that you dont need to know the type that is being used....
It looks like what you want is in fact not a Generic class, but an interface with a number of different implementations. But maybe it would become clearer if you stated your actual, concrete goal.
I agree with Visage. Generics is for compile-time validation, not runtime dynamic typing. Sounds like what you need is really just the factory pattern. But if your "do this" isn't instantiation, then a simple Enum will probably work just as well. Like what Michael said, if you have a slightly more concrete example, you'll get better answers.

Categories

Resources