Secular wanderer: a programmer who focuses on technical research
Say what I said before
As one of the oldest and most fundamental technologies in Java, I think we need to know more about it
reflection
Reflection is the technique of analyzing the properties and methods of a class through binary bytecode
Class loading process
loading
- Pass the class file
java
Load the binary data in the class into memory - create
Class
Object and points a reference to the opened binary memory space
linking
There are three steps:
- Verify that the class file conforms to the standard
Sublime opens the class file and you can see the hexadecimal format, but I won’t write it here, so you can open it for yourself
Cafe Babe 0000 0034 + + + + + + + + + + + + + + + + + + + + + + + + + +Copy the code
- Assign default values to member variables
public class T {
int i = 8;
public static void main(String[] args) {}}Copy the code
The I here is going to be assigned to the default value of int 0, which is int I = 0;
- Symbolic references used in the constant pool are converted to usable memory content
initializing
Here is how the class is actually initialized, in this step:
- Member variables assign initial values
<init>()
Method is called, the wholeClass
loaded
It doesn’t matter if you don’t understand it. It’s just a reference.
There are a lot of loading processes, such as’ class loaders’, ‘parent delegate mechanisms’, etc., which are discussed in more detail in the JVM
annotations
Tags that begin with @ describe classes, fields, methods, etc. are annotations, such as:
// This is it
@Override
public int hashCode(a) {
return super.hashCode();
}
Copy the code
Here @override is an annotation, provided by the JDK. Annotations can be customized. Let’s use @Override to see what elements a custom annotation contains
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
Copy the code
First of all, it’s embellished by the at sign interface, and then there’s other stuff
- @Target
@target indicates the scope of the annotation we defined, and the full scope can be seen with ElementType:
public enum ElementType {
/** applies to classes, interfaces, enumerated classes */
TYPE,
/** represents fields, variables, including enumeration properties */
FIELD,
/** method */
METHOD,
/** 参数 */
PARAMETER,
/** constructor */
CONSTRUCTOR,
/** Local variable */
LOCAL_VARIABLE,
/** Annotation type */
ANNOTATION_TYPE,
/** does not apply to general classes, but to fixed files in package-info.java */
PACKAGE,
/** * Type parameter declaration **@since1.8 * /
TYPE_PARAMETER,
TYPE_USE
}
Copy the code
Multiple scopes can be defined
- @Retention
Indicates how long annotations for annotated types will remain. If there are no reserved comments on the annotation type declaration, the RetentionPolicy defaults to retentionpolicy.class and contains the following sections:
public enum RetentionPolicy {
/** * The annotation is discarded by the compiler */
SOURCE,
/** * Annotations remain, but will not be loaded by the JVM */
CLASS,
/** * is retained for the duration of the JVM, so it is possible to get annotated annotations */ by reflection
RUNTIME
}
Copy the code
The above two are the most important, and the other two should also have a look:
- @Documented
Generated Javadoc documentation will be used
- @Inherited
A subclass may inherit this annotation from its parent class
Specific method of reflection
Based on the object
public class Person {
private String kkals;
public String getKkals(a) {
return kkals;
}
public void setKkals(String kkals) {
this.kkals = kkals; }}public class Emp extends Person implements Comparable<Emp>{
public String azk = "121";
private Long id;
private String name;
private Date birthd;
private Emp(Long id) {
this.id = id;
}
public Emp(a) {}public Emp(Long id, String name, Date birthd) {
this.id = id;
this.name = name;
this.birthd = birthd;
}
public Long getId(a) {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName(a) {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthd(a) {
return birthd;
}
public void setBirthd(Date birthd) {
this.birthd = birthd;
}
@Override
public java.lang.String toString(a) {
return "Emp{" +
"azk=" + azk +
", id=" + id +
", name=" + name +
", birthd=" + birthd +
'} ';
}
@Override
public int compareTo(Emp o) {
return 0; }}Copy the code
Get the Class object
private static void getClazz(a) throws ClassNotFoundException {
// Load the Class object with the full package name + the Class nameClass<? > clazz = Class.forName("java.lang.String");
printInfo(clazz);
// Load the class object as a.class
clazz = Emp.class;
printInfo(clazz);
// This is a little low, so the idea will be yellow, and then change to.class mode
clazz = new Emp().getClass();
printInfo(clazz);
// Not suitable for ordinary objects
Class<Integer> type = Integer.TYPE;
printInfo(type);
}
private static void printInfo(Class
clazz) {
System.out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
System.out.println("Package name:" + clazz.getPackage());
System.out.println(Class full name: + clazz.getName());
System.out.println("Class name:" + clazz.getSimpleName());
System.out.println("Java specification compliant names:" + clazz.getCanonicalName());
System.out.println("Class modifier:" + clazz.getModifiers());
System.out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
}
Copy the code
The above four ways, more are recommended to use the first and second way
For class modifiers, if we want to determine if the class or attribute is what we want, we can compare it like this:
(clazz.getModifiers() & Modifier.PRIVATE) ! =0;
Copy the code
Returns true, indicating that the specified modifier is modified, or not otherwise
Get member variables
private static void getField(a) throws ClassNotFoundException{ Class<? > clazz = Class.forName("Emp");
// The main method
Field[] fields = clazz.getFields();
for (Field field : fields) {
printFiledInfo(field);
}
System.out.println("================== gorgeous delimiter =====================");
// The main method
Field[] declaredFields = clazz.getDeclaredFields();
for(Field declaredField : declaredFields) { printFiledInfo(declaredField); }}private static void printFiledInfo(Field field) {
System.out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
System.out.println("Variable name:" + field.getName()); // The variable name azk
System.out.println("Variable type:" + field.getType()); // The variable type is class java.lang.string
System.out.println("Variable modifier:" + field.getModifiers()); // modifiers 1
System.out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
}
Copy the code
GetFields () and getDeclaredFields() :
- The former can only be retrieved from the Class object
public
Modifies a variable, and nothing else can be modified - The latter can get variables of all types in the Class object, but not the parent
Get data for variables
// Public can be obtained directly
Field fieldId = clazz.getDeclaredField("azk");
final Object o = clazz.newInstance();
System.out.println(fieldId.get(o));
// The private type can be accessed only if setAccessible is set to true, otherwise an error will be reported,
// After fetching, it is recommended to set it to false
Field fieldId = clazz.getDeclaredField("id");
final Object o = clazz.newInstance();
/ / important
fieldId.setAccessible(true);
System.out.println(fieldId.get(o));
/ / important
fieldId.setAccessible(false);
Copy the code
Get common methods
private static void getMethods(a) {
Class<Emp> empClass = Emp.class;
// We can get all the objects in the Object, including the parent Object and the method in Object
Method[] methods = empClass.getMethods();
for (Method method : methods) {
System.out.println(method.getName());
System.out.println(method.getReturnType());
System.out.println(method.getModifiers());
}
System.out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
// Only methods in the current class can be retrieved
methods = empClass.getDeclaredMethods();
for(Method method : methods) { System.out.println(method.getName()); System.out.println(method.getReturnType()); System.out.println(method.getModifiers()); }}Copy the code
Operation method
// If there are arguments, then getMethod follows the type of the argument
Method setId = empClass.getMethod("setId", Long.class);
setId.invoke(emp, 1L);
// There are no arguments
Method method = empClass.getMethod("getId");
System.out.println(method.invoke(emp));
Copy the code
GetDeclaredMethod () is recommended if parent classes and Object methods are not required.
Get constructor
Constructor<? >[] constructors = clazz.getConstructors();for(Constructor<? > constructor : constructors) { System.out.println(constructor.getName()); } System.out.println("= = = = = = = = = = = = = = = = = = = = = = = =");
constructors = clazz.getDeclaredConstructors();
for(Constructor<? > constructor : constructors) { System.out.println(constructor.getName()); }Copy the code
Generate objects from the constructor
Constructor<? > constructor = clazz.getDeclaredConstructor(Long.class, String.class, Date.class); System.out.println(((Emp)constructor.newInstance(1L."kkals".new Date())).toString());
Copy the code
To obtain annotations
// Get all the annotations on the class
Annotation[] annotations = clazz.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
// Get the specified annotation object
Annotation declaredAnnotation = clazz.getDeclaredAnnotation(Annotation.class);
Copy the code
Determines whether a specified annotation exists
if (clazz.isAnnotationPresent(Annotation.class)) {
System.out.println("The annotation exists.");
}
Copy the code
Example: simple implementation of ORM framework
Define setting table name annotations
@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Table {
public String tableName(a) default "";
}
Copy the code
Define set column name annotations
@Target(value = {ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String columnName(a) default "";
}
Copy the code
Definition ignores column name annotations
@Target(value = ElementType.FIELD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Transate {
}
Copy the code
Utility class: cache class
public class EntityCacheUtil {
private static finalMap<Class<? >, Field[]> FIELD_MAP =new HashMap<>();
private static finalMap<Class<? >, String> TABLE_NAME_MAP =new HashMap<>();
static {
try {
EntityCacheUtil.init();
} catch(Exception e) { e.printStackTrace(); }}/** * get the table name */
public static String getTableName(Class
clazz) {
String tableName = TABLE_NAME_MAP.get(clazz);
// The current tableName is not null
if (StringUtils.isNotBlank(tableName)) {
return tableName;
}
Table annotation = clazz.getDeclaredAnnotation(Table.class);
if (null! = annotation) { tableName = annotation.tableName(); }else {
tableName = toLine(clazz.getSimpleName());
}
TABLE_NAME_MAP.put(clazz, tableName);
return tableName;
}
/** * Convert the humped class name to an underscore */
public static String toLine(String simpleName) {
final char[] chars = simpleName.toCharArray();
StringBuilder sb = new StringBuilder();
for (char c : chars) {
if (Character.isUpperCase(c)) {
sb.append("_");
}
sb.append(c);
}
if (sb.toString().startsWith("_")) {
sb.delete(0.1);
}
return sb.toString().toLowerCase();
}
/** * Get all fields * of this class@throws IOException
* @throws ClassNotFoundException
*/
public static void init(a) throws IOException, ClassNotFoundException {
// Change the package name to its own
finalList<Class<? >> fileList = PackageUtil.INSTANCE.getFileList("zopx.top.study.reflect.entity", Serializable.class, true);
fileList.forEach(item -> FIELD_MAP.put(item, item.getDeclaredFields()));
}
public staticMap<Class<? >, Field[]> getFieldMap() {returnFIELD_MAP; }}Copy the code
PackageUtil is a Class that scans all Class objects in a package and caches them. The code is too long, but the poM dependencies are shown below
<dependency> <groupId>top.zopx</groupId> <artifactId>tools-boot-starter</artifactId> <version>1.1.4</version> </dependency> Copy the code
Concrete implementation mode
Define the interface first, which is pretty much the way we use it
public interface BaseDao<T extends Serializable.K> {
/** * save */
int save(T entity);
/** * modify */
int update(T entity, K id);
/** * delete */
int deleteById(K id);
/** * get the list */
List<T> getList(a);
/** * Obtain details by ID */
T getById(K id);
}
Copy the code
The implementation class
public abstract class BaseDaoImpl<T extends Serializable.K> implements BaseDao<T.K> { Class<? > clazz;public BaseDaoImpl(a) {
// Get the type of the generic object in the class
Type type = this.getClass().getGenericSuperclass();
if (type instanceofParameterizedType) { ParameterizedType p = (ParameterizedType) type; clazz = (Class<? >) p.getActualTypeArguments()[0]; }}@Override
public int save(T entity) {
// 1. Get the table name and column
String tableName = EntityCacheUtil.getTableName(entity.getClass());
Field[] fields = EntityCacheUtil.getFieldMap().get(entity.getClass());
// insert into user_acc(user_id, login_name, login_pwd) value(? ,? ,?) ;
StringBuilder sql =
new StringBuilder("insert into ")
.append(tableName)
.append("(");
List<Object> valueList = new ArrayList<>(fields.length);
for (Field field : fields) {
// If Transate exists in the field, the setting will be skipped
Transate transate = field.getDeclaredAnnotation(Transate.class);
if (null! = transate)continue;
Column column = field.getDeclaredAnnotation(Column.class);
String columnName = "";
if (null == column) {
// If no field name is set for this field, modify the hump
columnName = EntityCacheUtil.toLine(field.getName());
} else {
columnName = column.columnName();
}
sql.append(columnName).append(",");
// Get the value from field
field.setAccessible(true);
try {
valueList.add(field.get(entity));
} catch (IllegalAccessException e) {
System.out.println(e.getMessage());
}
field.setAccessible(false);
// The second way is to call invoke with the get method to get concrete data
// try {
// Method method = entity.getClass().getMethod(getMethodName(field.getName()));
// valueList.add(method.invoke(entity));
// } catch (Exception e) {
// System.out.println(e.getMessage());
/ /}
}
sql.deleteCharAt(sql.length() - 1).append(") value (");
valueList.forEach(value -> sql.append("? ,"));
sql.deleteCharAt(sql.length() - 1);
sql.append(")");
System.out.println(sql.toString());
System.out.println(valueList);
return 0;
}
private String getMethodName(String fieldName) {
return "get" + fieldName.substring(0.1).toUpperCase() + fieldName.substring(1);
}
@Override
public int update(T entity, K id) {
return 0;
}
@Override
public int deleteById(K id) {
return 0;
}
@Override
public List<T> getList(a) {
return null;
}
@Override
public T getById(K id) {
System.out.println(clazz.getCanonicalName());
return null; }}Copy the code
As you can see, we just printed out the SQL statement at the end, nothing else. We’ll talk about MySQL and JDBC, and we’ll come back to this example
The other methods are not written, but a method called save() can also string the above things together, so you can try to complete the other methods yourself
Actual invocation
public interface UserAccDao extends BaseDao<UserAcc.Long> {}public class UserAccDaoImpl extends BaseDaoImpl<UserAcc.Long> implements UserAccDao {}public class Test {
public static void main(String[] args) {
UserAccDao userAccDao = new UserAccDaoImpl();
UserAcc entity = new UserAcc();
entity.setUserId(1L);
entity.setLoginName("123");
entity.setLoginPwd("12345");
userAccDao.save(entity);
userAccDao.getById(1L); }}// insert into user_acc(user_id,login_name,login_pwd) value (? ,? ,?)
/ / [1, 123, 12345]
// zopx.top.study.reflect.entity.UserAcc
Copy the code
The last word
Well, that’s the end of reflection. Let’s talk about MySQL and JDBC