Want this course?
Classes and Reflection
Course: JVM Fundamentals for Clojure
Java has a good story for reflection: just ask the object for its class and ask the class for a list of methods. Voilà! You know what methods you can call. This lesson demonstrates reflection with some examples.
Classes and introspection. Since we're on the jvm and it's hosted, closure gives you ways to figure out and manipulate classes and figure out what the classes can do. So, the most basic way of using classes is just to name them.
So classes in Java, it's not a syntax rule, but typically they will start with a capital letter. And they actually have a package and a class name. The package is usually lowercase, there's some dots, and the last thing is the name. And if something is imported, and java.lang is imported automatically, you can just refer to the class name, otherwise you'll have to fully qualify it, like, using the whole package.
Another thing, so let's give an example of that, InputStream, you see, it doesn't compile, but if I do java.io.InputStream, it will be recognized. Now this is because these classes are already loaded so that you can refer to them. If you need to load the class, you need to do an import statement, and we'll go over that in a different lesson. Alright, so one thing that we can do is, if we have an object, so there's a class called Object, let's look at that. This is the top of the class hierarchy.
Java has a class hierarchy and it's a tree and at the top of the tree is Object so everything in Java, except for primitives, meaning int, float, double, byte, those kinds of things, those are all primitives, they don't have a class. But usually closure will coerce them to something that has a class. So everything that you'll normally deal with is an object or its a primitive. So if we get an object, we might not know what we have, so we need to introspect. And usually you don't want to introspect so much, but sometimes you have to. At the rebel though, it's very handy. So let's say I have this, I can see what I have. Oh, sorry. Instance I messed up, okay, put it up. So this is to tell me whether what I have is a string. Of course, there's something built in called string which is basically the implementation of it, but I can put any class here, this could be any class and I could tell if I have that instance.
It's very useful sometimes to check to assert that you have something, and we'll do assertions in another lesson. But what if I just want to know, what do I have? Not do I have something of a given type. So if I have instance, I just want to give a couple other examples. Instance? Long Right, I can see if I have a long. It comes in handy. But what if I'm at the rebel and I want to know what class something is.
So I have some random object and, let's say "hello" is my random object, it will tell me its a java.lang.String If I have class 123, what is the type? java.lang.Long Okay, and you can do this for any object and it'll tell you what it is. Now what do you do with that class? I can refer to the class anytime using this long notation or the short notation, closure will figure out that I'm talking about a class or I can refer to it like this and I can get all of the super classes. So, what are the super classes of String? So it's going to give me a set, and it lists all the classes in the tree all the way up to the root, from this class, String, all the way to the root.
So you see the root is Object, but it's also an instance of CharSequence, of Comparable, of Serializable, and I can do this with any class. Let's go to the repl for that next example, because it's a little bit harder to show in code. Right. Okay, so let's say I have the String class... Well, let's see, no, we'll do it like this. I wanna get the methods on the String class. What does this do for me? What can I call on it? So, there. Now what is it returning? This is the funny syntax to show that its an array. Its an array of methods. Right, this open square bracket L means its an array and then it tells me the type of the array. Okay, so, that's not very useful to me because I can't even see the context.
The thing is, in closure, arrays can be used like sequences, so I can do this and now I see all of the methods on that object, on that class, sorry. So I can then, let's say, instead of turning into a vec, I can do doseq method, and these are method objects, you see, this is the notation that you're getting a pure Java object and then its type is method and then it shows you the name just to help you out. So I can do a prn on each method. There we go. So this is printing one per line, which is a little better, but notice they're also out of order, I'm still printing this whole bit that doesn't really help, it's kind of useless to me, so I'm going to just print, let's see, .getName Let's do this, print line. There, so that's just the name.
Now of course the name doesn't have the type signature, right? So what is the method to call to get the type signature? Well, I'm going to do something kind of meta, and I'm going to get this type here, this is meta, and I'm going to put it here. So now I see all the methods on the class Method. See, this is reflection, and this is one of the cool things about Object Oriented Programming is that everything is an object, so you can ask it what it can do. You don't want to do this so much at runtime, but at the repl its perfect.
So let's see. We had getName, right? getName, TypeParameters, and ReturnType, but what is getParameterTypes, getParameterCount? Let's see if we can do getParameterTypes and print that out. So we're going to print the name and lets say, a paren, and then .getParameterTypes on the method. Ah, of course, that's just an array of classes, so lets turn that, lets get rid of the parens here, and lets put that in a seq. Okay. So nil, that's not actually what we want, we want... We don't want nil, we want into... That. No that's gonna make them backwards, isn't it? Let's start with seq. Okay. Cause I just wanna have empty lists, right? Two closed, open close paren.
Alright, let's see what we got here. I still want 'em in alphabetical order, so I'm gonna do sort-by now I need to do .getname % and lets put a nice new line here, now I'm sorted by name and I can see all of the methods here. This is string, and this is what it does, it's cool. So I hope you've seen the value of being able to introspect at the repl. It's not always the best way to see it, for instance, you can see all this in the docs, but sometimes you just want to stay in you repl and work with what you've got.