Forums Register Login

Java Generics

+Pie Number of slices to send: Send
Hi,

I am new to generics and wanted to know what is meant by Class<?>. For example if I define a variable say private class<?> test then what is the significance of the wildcard ? there. I did read a little about generics but still bot able to understand what is this notation class<?>. Also, since I don't know what exactly is this class how would I type cast an object O to test when its type is class<?>. Can someone please explain this? Its's quite confusing and I am unable to understand this part.

Thanks!!
+Pie Number of slices to send: Send
Hi,

Check this out

Vishal
1
+Pie Number of slices to send: Send
Your question is one of those from Angelika Langer's Java Generics FAQ, which is an excellent resource with everything you ever wanted to know about generics, although it's not always easy to understand:

What is the difference between the unbounded wildcard parameterized type and the raw type?

The answer is that they are almost the same, but if you use an unbounded wildcard <?> the compiler will give you an error in certain situations instead of just a warning, which you would get when you would use the raw type without any generics. Note that raw types really exist only because of compatibility with old Java versions, which didn't have generics - you really should avoid using raw types as much as possible in newly written code.
1
+Pie Number of slices to send: Send
 

N Tiwa wrote:I am new to generics and wanted to know what is meant by Class<?>. For example if I define a variable say private class<?> test then what is the significance of the wildcard ? there. I did read a little about generics but still bot able to understand what is this notation class<?>.


OK, a few things to understand:
1. Java is case-sensitive, so Class<?> and class<?> are NOT the same thing (in fact, the last one has no meaning that I know of).
2. Generics is a big subject, so you really need to read the tutorials completely, not just "a little". In this case, 'a little knowledge is a dangerous thing'.

My advice: understand how generics uses specific types (ie, Class<T>) first, before you venture into the wonderful world of wildcards.
Go through the examples for those thoroughly and make sure you understand them before going on to the next part. The tutorials are actually arranged quite well so that you build up your knowledge incrementally, but you really do need to read them from start to finish.

HIH

Winston
+Pie Number of slices to send: Send
Thanks everyone for you suggestions. I did start reading more on this. I was trying this very basic example, which is also related to my problem I posted before and wanted to know what am I doing wrong here-
I created2 class Generic and Data. I have created this variable Class<?> test which can possibly take any object as I have specified wildcard there (Forgive me for any wrong terminology I am using here, I am just trying to learn more to correct myself in future ). Now I have a very simple main method which is creating a class and then passing it to displayDetails method. It works fine and prints test class and test class name. But when I try to do a typecast it creates a problem. It says it cannot find symbol Class test. But, I don't understand when it is able to do that in the statements just written before that (I compiled it with and without the type casting statement) why it complains that it cannot find test while doing a type cast although if I try to print test.getClass().getName() it works perfectly fine?? I would really appreciate if someone can point my mistake here. Thanks!!!
+Pie Number of slices to send: Send
I don't see any casting in your code. Did you perhaps mean the line of code which is commented out?



If so, that's nothing to do with Generics. Casting requires the name of a class inside the parentheses. You can't put the name of a variable there.
+Pie Number of slices to send: Send
Yes the commented part is what I meant.. when I do (test)this it says it cannot resolve test to a type. I defined test to be class<?> test. So basically I don't know the type of test in advance it comes in as part of constructor call and it can be anything. Now when I get the type I try to cast "this" to test. But, that's where i get this error "cannot resolve test to a type".
+Pie Number of slices to send: Send
Well, as I already said, you have to put a class name into the parentheses when you cast. This is so the compiler knows what type you're going to be casting to. When you cast, to File for example, you're saying "Hey compiler, I know this expression doesn't look like it's a File object, but trust me, when the code runs it's going to be a File object, so please treat it like one."

In other words, casting to an unknown type doesn't make any sense. What were you trying to achieve with your cast attempt?
+Pie Number of slices to send: Send
I need to know the type of test class so that I can cast an object to that type. But, From the attempts I am making I am not able to retrieve the type of test class.
As you mentioned casting to an unknown type doesn't make any sense, I have defined test as Class<?> test. So basically the type is unknown to me at this time and I will know that type when something is passed in to the constructor which will define the type of the class I have defined. so,I need to know what is <?> in order to cast an object to this type. I am not sure what you mean by passing name into parentheses. sorry for asking basics but I am not able to get the point. Please help!
+Pie Number of slices to send: Send
Parentheses? It's what you did:

System.out.println("===Trying to cast===="+(test)this);

The characters on either side of the word "test" in that statement are called parentheses.

And no, you don't need to cast to an unknown type. That's because the compiler only lets you cast to a type which you specify at compile time. Maybe you need to do something else, but it isn't casting. So what, exactly, is it that you need to do? You seem to be saying that you need to have the compiler treat an expression as if it had a type which isn't known until run time, which of course can't happen. So whatever you need to do, it can't involve the compiler and it can't be casting.

In the particular example you posted, you have a Generic object (that's what "this" means in that code). So apparently you want to treat that object of type Generic as if it were an object of some other type?
+Pie Number of slices to send: Send
Okay Let me re-state my problem. I am sorry my statements were a little confusing. Here is what I am trying to do-

I have a class let's say A. This is the basic structure
class A{
private final Class<?> test;
public A(Class<?> test){
this.test = test;
}
public void castObject(){
System.out.println(test.getClass().getName()); //This method should display the class name
//Need to write code here which is what will do cast
}
}

Now there is mainly just one issue that I am trying to solve here -
I have a constructor which takes 2 argument specifically it is the StandardMBean constructor. Here is an example of what is happening-
Source - http://www.oracle.com/technetwork/java/javase/adoptionguide-137484.html
For example, the following code will no longer compile:
Object impl = new SomethingImpl(); Object mbean = new StandardMBean(impl, SomethingMBean.class); mbeanServer.registerMBean(mbean, objectName);
The compiler will reject the new StandardMBean line with a message like this:
Test.java:10: cannot find symbol symbol: constructor StandardMBean( java.lang.Object, java.lang.Class<com.example.SomethingMBean>) location: class javax.management.StandardMBean
Recommended Fix
The fix is either to change the declaration of impl from Object to SomethingImpl or SomethingMBean or to add a cast in the call to the constructor:
Object mbean = new StandardMBean((SomethingMBean) impl, SomethingMBean.class);

I am this same situation. In order for my code to compile I need to add cast in the constructor. For my case I also have this same issue but the problem is SomethingMBean.class is unknown in my case as it is defined as - Class<?> . I don't know what is the actual name of the class or the type. Now, in order to compile this code I must find the type and then do a type cast. Is a problem statement a little clear now?


+Pie Number of slices to send: Send
Okay, I see. So right now you have something like this:



but that doesn't compile. However you're somehow guaranteed that the "impl" object will in fact be an object of the "beanType" type. In this case you need this:



At least, I think that might work. I haven't tried it myself. Note that the Class.cast(Object) method will throw a ClassCastException at runtime, just as a failed cast would do.
+Pie Number of slices to send: Send
Hi Paul,

Thanks for your suggestion. I did try the approach you mentioned but in that case the error I get is the same. Also I see in the log it says it is getting StandardMBean(Java.lang.Object, Java.lang.class). But, as per the documentation we should convert both of them to class.
Recommended Fix
The fix is either to change the declaration of impl from Object to SomethingImpl or SomethingMBean or to add a cast in the call to the constructor:
Object mbean = new StandardMBean((SomethingMBean) impl, SomethingMBean.class);


In this case we are just getting an object. I did try something else which is the object that I got from doing - beanType.cast(impl) , I tried to do a beanType.cast(impl).getClass() so that both of them are of same type. But again the issue here is more like I get an error saying-

cannot find symbol : constructor StandardMBean(java.lang.class<capture#342 of ? extends java.lang.object>, java.lang.class<capture#868 of ?>)
There are 2 problems I feel-
1. since the class was defined a generic one using class<?> I cannot know the what type is this class.
2. If beanType.cast(impl) did a type cast of impl to the beanType then when I do a .getClass I should get class type for beanType .

If 2 is true then I should have StandardMBean(java.lang.class<capture#342 of ? >, java.lang.class<capture#342 of ?>) why is the capture # different ?? Can someone please suggest what might have been wrong here?

+Pie Number of slices to send: Send
Yes, I suspected that might happen. But here's the root cause of your problem:



So why don't you address this statement as the problem? Presumably the code you're talking about is contained in a method whose signature is like this:



and that code is being called by a variety of code which creates various MBean implementations. So why not change that to



and change each caller of that code to provide the class of its MBean implementation as the second parameter?
+Pie Number of slices to send: Send
 

N Tiwa wrote:I have a class let's say A. This is the basic structure
class A{
private final Class<?> test;
...


Well that seems odd to me right there. Wildcards are generally used for parameters, not fields.

I'm also still not quite sure exactly what you're trying to achieve, since StandardMBean seems to involve reflection, with is pretty much the antithesis of generics; but I'm certainly no expert when it comes to "beanifying".

Looking only at your example, it would seem to me that something likemight be what you want; and personally, I'd make the constructor private and add a factory method, viz:but the whole business seems awfully clunky to me.

Mind you, I HATE reflection.

It's also worth noting that Java is statically typed, so if you're looking for some magic "universal caster", methinks you've chosen the wrong language.

Winston

PS: You might also want to think of a better class name than 'A'.
+Pie Number of slices to send: Send
@Paul - The problem is a little different than what you have specified. I have this constructor which is called from other class which sets that value for my Class<?> test variable. After this is done I have a method that creates Bean-


Now, in order to make this work I just have one option that is to cast. I wanted to know is there a way to get the Type of this class<?> test variable i.e Class name for this so that I can easily convert this to that type and solve the problem as this is what is suggested in the fix - http://www.oracle.com/technetwork/java/javase/adoptionguide-137484.html

If not is there any other way if I cannot refactor other chunks of the code other than juts this class?? I know this is a difficult question to answer as I have limited context for eveyone here, but I would really appreciate if someone can help me understand this issue which I am unable to solve
+Pie Number of slices to send: Send


As one of those links you posted says, the compiler wants to check that the object "this" is an instance of the type "test". And (I think) the generic type defined in the class heading forces that to be the case, in a way that the compiler can recognize.

You might even be able to get away with "Class BeanData<T>", for that matter. I'm not sure why I think "? extends T" would be necessary, so try the simpler way first.
+Pie Number of slices to send: Send
You didn't mention that you were subclassing BeanData, but I assume that you are. Then your subclass would look like this:


+Pie Number of slices to send: Send
Thanks Paul for your suggestion. But, I am not sub classing the way you have specified. So here is the situation-



So SomeData is a class which is not related to this Bean Generation except for the fact that it has a constructor that takes in the Generic Class assigns it to it's private variable mbeanInterface and then has this getBean method. Knowing this much how can I do the typecast? I am thinking along the typecast path as it is the only suggested fix. I am not sure if if understand what you meant by -

As one of those links you posted says, the compiler wants to check that the object "this" is an instance of the type "test". And (I think) the generic type defined in the class heading forces that to be the case, in a way that the compiler can recognize.

You might even be able to get away with "Class BeanData<T>", for that matter. I'm not sure why I think "? extends T" would be necessary, so try the simpler way first.


With the information I have can we typecast this to mBeanInterface's class type (which is unknown to us)?? Any help is greatly appreciated!
+Pie Number of slices to send: Send
As I already said, the compiler needs to be able to verify that an instance of class SomeData implements the class of mbeanInterface. It can't do that unless you tell it what that class is. So "?" isn't good enough. I'm still guessing because you're using made-up class names, but from that code all we know is that SomeData implements Data. So presumably you need



to make that happen. I don't know what "A" and "MoreData" mean but they don't appear to be useful here. Of course as I said your obfuscation of the class names leaves me to guess at what you're trying to do.

But if that's the only class you have (you said no subclassing) then you might as well do



and skip the parameter-passing.

+Pie Number of slices to send: Send
Hi Paul, I completely understand what you are trying to say here. But, the things we both are saying here I think is the same i.e. "?" is not good enough. I am using made up names here and I understand that it is causing some confusion but I did not write that code so that is why I am not able to provide clear details. But, I think I have answers for what you are asking-
1.

As I already said, the compiler needs to be able to verify that an instance of class SomeData implements the class of mbeanInterface. It can't do that unless you tell it what that class is. So "?" isn't good enough. I'm still guessing because you're using made-up class names, but from that code all we know is that SomeData implements Data. So presumably you need



For this part - You are right SOmeData implements Data but like i mentioned it's just like a holder class which had a predefined structure and the constrcutor of this class will be taking class<?> mbeanInterface as parameter and I cannot change that part. The reason for that is I have another class



So this class is basically providing us with the value of Class<?> mBeanInterface. From this code at least I can say that the ? is mBeanInterface...Is this assumption correct??

don't know what "A" and "MoreData" mean but they don't appear to be useful here. Of course as I said your obfuscation of the class names leaves me to guess at what you're trying to do.

But if that's the only class you have (you said no subclassing) then you might as well do

view plaincopy to clipboardprint?

return new StandardMBean(Data.class, mbeanInterface);



For this Part - I agree A and MoreData are not making any sense but I was trying to give you the overall structure of the class. I know things are a little confusing and I am trying to understand. I am sorry if my explanation is not very clear. I will try to be better.

I think the first part might help you to give a better picture of my problem. ALso, I tried Data.class but it gives me same error as before i.e. need to cast it in mBeanInterface.
+Pie Number of slices to send: Send
 

N Tiwa wrote:the constrcutor of this class will be taking class<?> mbeanInterface as parameter and I cannot change that part



Then it looks like your original project -- what was it? I've lost track. Converting to Java 6? -- anyway, whatever it was, you can't proceed with that. Because it looks like that's what you will have to change.
+Pie Number of slices to send: Send
@Paul : I didn't mean to say I cannot change that part but it's just that I was trying to tell that I don't own the code...so changing something might break something else. But, I am trying to dig in more details so that I can try to do the fix you recommended..may be I am not able to mention the problem correctly. I will try to find a solution ans update post with results..Thanks again for your guidance...I will try the approaches you mentioned and will post my results shortly. Thanks again!
Space pants. Tiny ad:
a bit of art, as a gift, the permaculture playing cards
https://gardener-gift.com


reply
reply
This thread has been viewed 1484 times.
Similar Threads
generics
Generics
Generics
Generics
Generics
More...

All times above are in ranch (not your local) time.
The current ranch time is
Mar 28, 2024 10:54:18.