Java reflection mechanism instance code sharing
- 2020-11-26 18:47:23
- OfStack
The purpose of this article is to provide a comprehensive introduction to Java reflection. Hopefully, you will have a comprehensive understanding of Java reflection.
Before reading this article, you can refer to reunderstanding Java generics.
preface
The Java reflection mechanism is a very powerful feature that can be seen in many large projects such as Spring. The reflection mechanism enables us to obtain the type information of objects at run time, which enables us to implement design patterns such as factory patterns and proxy patterns, as well as solve vexing problems such as Java generic erasure. In this paper, we apply the reflection mechanism of Java 1 from the perspective of practical application.
Reflection basis
p.s: This article requires a certain level of understanding of API as a reflection mechanism. If you have not been exposed to Quick before, it is recommended to read Quick Start in the official documentation.
Before we apply the reflection mechanism, let's first look at how to get the reflection class corresponding to 1 object
Class
In Java we have three ways to get a reflection class for an object.
Through the getClass method
In Java, one for each
Object
There is one
getClass
Method, we can get the corresponding reflection class of this object through getClass method:
String s = "ziwenxie";
Class<?> c = s.getClass();
We can also call
Class
Static methods of a class
forName
:
Class<?> c = Class.forName("java.lang.String");
Using class.
Or we could just use it
.class
:
Class<?> c = String.class;
Get type information
We mentioned at the beginning of this article that one of the great benefits of reflection is that it allows us to get the type information of an object at run time. Let's look at this in detail with an example.
First of all, we are
typeinfo.interfacea
Create a new interface below the package
A
:
package typeinfo.interfacea;
public interface A { void f(); }
And then we went to
typeinfo.packageaccess
Create a new interface below the package
C
, the interface
C
Inherits from interface
A
, and we have also created several other methods for testing. Note that the permissions for the following methods are different.
package typeinfo.packageaccess;
import typeinfo.interfacea.A;
class C implements A {
public void f() { System.out.println("public C.f()"); }
public void g() { System.out.println("public C.g()"); }
protected void v () { System.out.println("protected C.v()"); }
void u() { System.out.println("package C.u()"); }
private void w() { System.out.println("private C.w()"); }
}
public class HiddenC {
public static A makeA() { return new C(); }
}
in
Object
2
In the method we used several new API, among them
Object
3
A method used to get the Class class to refer to the object based on the method name, which we then call
Object
4
Methods that pass into the actual object can trigger the object's related methods:
package typeinfo;
import typeinfo.interfacea.A;
import typeinfo.packageaccess.HiddenC;
import java.lang.reflect.Method;
public class HiddenImplementation {
public static void main(String[] args) throws Exception {
A a = HiddenC.makeA();
a.f();
System.out.println(a.getClass().getName());
// Oops! Reflection still allows us to call g():
callHiddenMethod(a, "g");
// And even methods that are less accessible!
callHiddenMethod(a, "u");
callHiddenMethod(a, "v");
callHiddenMethod(a, "w");
}
static void callHiddenMethod(Object a, String methodName) throws Exception {
Method g = a.getClass().getDeclaredMethod(methodName);
g.setAccessible(true);
g.invoke(a);
}
}
We can tell from the output, no matter what
Object
5
.
Object
6
.
Object
7
or
Object
8
Methods, which we can all call freely through the reflection class. Of course, just to show the power of reflection, this technique is not recommended in practice.
public C.f()
typeinfo.packageaccess.C
public C.g()
package C.u()
protected C.v()
private C.w()
The application practice
We have the following business scenario where we have a generic collection class
Object
9
, we need to count each specific in this collection class
getClass
0
How many are there? Due to the generic erasure of Java, note the similarity
getClass
1
This is definitely not the case, because JVM will treat all objects in the collection at run time after the compiler has done static type checking
getClass
0
But you don't know
getClass
0
What does it represent
getClass
4
or
getClass
5
, so by run-time the object's type information is all but lost. p. s: About generic erasers: I explained it in detail in my last article.
To implement our example above, let's first define a few classes:
public class Pet extends Individual {
public Pet(String name) { super(name); }
public Pet() { super(); }
}
public class Cat extends Pet {
public Cat(String name) { super(name); }
public Cat() { super(); }
}
public class Dog extends Pet {
public Dog(String name) { super(name); }
public Dog() { super(); }
}
public class EgyptianMau extends Cat {
public EgyptianMau(String name) { super(name); }
public EgyptianMau() { super(); }
}
public class Mutt extends Dog {
public Mutt(String name) { super(name); }
public Mutt() { super(); }
}
The above
getClass
0
Class inherits from
getClass
7
.
getClass
7
The implementation of the class is a little bit more complicated 1, so we implemented
getClass
9
The interface, which redefines the rules for comparing classes, doesn't matter if it's not clear, we've abstracted it out, so it doesn't matter if we don't understand the implementation.
public class Individual implements Comparable<Individual> {
private static long counter = 0;
private final long id = counter++;
private String name; // name is optional
public Individual(String name) { this.name = name; }
public Individual() {}
public String toString() {
return getClass().getSimpleName() + (name == null ? "" : " " + name);
}
public long id() { return id; }
public boolean equals(Object o) {
return o instanceof Individual && id == ((Individual)o).id;
}
public int hashCode() {
int result = 17;
if (name != null) {
result = 37 * result + name.hashCode();
}
result = 37 * result + (int) id;
return result;
}
public int compareTo(Individual arg) {
// Compare by class name first:
String first = getClass().getSimpleName();
String argFirst = arg.getClass().getSimpleName();
int firstCompare = first.compareTo(argFirst);
if (firstCompare != 0) {
return firstCompare;
}
if (name != null && arg.name != null) {
int secendCompare = name.compareTo(arg.name);
if (secendCompare != 0) {
return secendCompare;
}
}
return (arg.id < id ? -1 : (arg.id == id ? 0 : 1));
}
}
Here we create an abstract class
Class
0
In the future, we're going to call
Class
1
The correlation can be obtained directly by the method
getClass
0
A collection of classes. This USES something we didn't mention above
newInstance()
Method, which returns an instance of the class that the Class class really refers to. What does that mean? For example, the declaration
new Dog().getClass().newInstance()
And direct
new Dog()
It's equivalent.
public abstract class PetCreator {
private Random rand = new Random(47);
// The List of the different getTypes of Pet to create:
public abstract List<Class<? extends Pet>> getTypes();
public Pet randomPet() {
// Create one random Pet
int n = rand.nextInt(getTypes().size());
try {
return getTypes().get(n).newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public Pet[] createArray(int size) {
Pet[] result = new Pet[size];
for (int i = 0; i < size; i++) {
result[i] = randomPet();
}
return result;
}
public ArrayList<Pet> arrayList(int size) {
ArrayList<Pet> result = new ArrayList<Pet>();
Collections.addAll(result, createArray(size));
return result;
}
}
Let's implement the above abstract class and interpret the code below 1. In the code below, we declare two collection classes,
allTypes
and
types
, including
allTypes
Contains all of the classes we declared above, but there are really only two of our specific types
Mutt
and
EgypianMau
So we really need
new
The pet that comes out is just
types
Contains the types that we will call later
getTypes()
You can get
types
All yo types contained in.
Class<?> c = Class.forName("java.lang.String");
0
The overall logic is complete, and finally we implement it to count the correlation in the set
getClass
0
The number of classes
TypeCounter
Class. Explanation 1
isAssignalbeFrom()
Method that determines whether a reflection class is a subclass or indirect subclass of a reflection class. while
getSuperclass()
As the name implies, you get the parent of a reflection class.
Class<?> c = Class.forName("java.lang.String");
1
conclusion
That's the end of this article on Java reflection mechanism example code sharing, I hope to help you. Those who are interested can continue to see this site:
Java programming printing shopping receipt implementation code
Implementation of references and dynamic proxies in Java in detail
Java programming simple eclipse code sharing
If there is any deficiency, please let me know. Thank you for your support!