• 周五. 12月 9th, 2022

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

Java advanced | generic mechanism and reflection principle

[db:作者]

1月 6, 2022

One 、 The concept of generics

1、 Basic case

Generics in Java It is widely used in , The most common is in a collection container , Let’s look at the basic usage first :

public class Generic01 {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>() ;
map.put(88,"hello") ;
// map.put("99","world") ; Input compile error
String value = map.get(88) ;
// Integer value = map.get(88) ; Output compilation error
System.out.println("value:"+value);
}
}

Make a statement map Type of container , And clearly define key and value The type of : Respectively Integer,String, This obviously does not reflect the special , We can compare the following usage :

Map newMap = new HashMap() ;
newMap.put("hello","world");
newMap.put(88,99);

Without specifying the type , All key value pairs default to Object type , When using such a container, you should always pay attention to different key Type and taken out value Value type , also value To do type conversion , In contrast, generic mechanisms are necessary .

May have a look Map Definition of interface :

public interface Map<K,V> {
V get(Object key);
V put(K key, V value);
}

stay Map Interface ,<K,V> Obviously no explicit type is specified , It just plays the role of type passing , namely K yes key The type of ,V yes value The type of , It’s clearly described in the source code above , Combined with the above case , stay Map Object declaration can be explicitly specified <K,V> The type of , It can also default to Object type .

2、 Generic description

Generics can be understood as taking data types as parameters , I.e. parameterized type , To improve code security , flexibility , Avoid type conversion ; The code is simple and clear , At the same time, it plays an important role in the scalability of the program .

First, a simple top-level interface is designed , Define only one callBack Method , And simple logic setting of in and out parameters , This kind of design Java The source code design can be seen everywhere , For example, the set system above :

/**
* Basic interface design
* @param <R> Return parameter type
* @param <V> Input parameter type
*/
interface CallBack<R,V> {
/**
* The callback method :V Methods into the reference ,R Method return value
*/
R callBack (V v) ;
}

In order to achieve specific business , And then expand downward based on the top-level interface , Two extension interfaces are declared here , As the interface of specific business class :

/**
* Extended interface design 01
*/
interface ExtCallBack01<R extends Integer,V extends List<String>>
extends CallBack<Integer,List<String>> {
@Override
Integer callBack (List<String> list) ;
}
/**
* Extended interface design 01
*/
interface ExtCallBack02<R extends Boolean,V extends Map<String,Long>>
extends CallBack<Boolean,Map<String,Long>> {
@Override
Boolean callBack (Map<String,Long> map) ;
}

In this way, specific business classes can be designed by extending the interface , Improve the flexibility and scalability of the program :

public class Generic02 {
public static void main(String[] args) {
new ExtCallBack01<Integer,List<String>>(){
@Override
public Integer callBack(List<String> list) {
list.add("hello");
return list.size();
}
};
new ExtCallBack02<Boolean,Map<String,Long>> (){
@Override
public Boolean callBack(Map<String, Long> map) {
map.put("Fire",119L) ;
return map.size()>0 ;
}
} ;
}
}

Through the above case , We can clearly feel the flexibility and power of generic mechanism .

3、 The essence of generics

Generics can be used in classes , Interface , Method , Parameters and so on , But the constraint is at the compile time of the code :

public class Generic03 {
public static void main(String[] args) {
DefEntry<String> defEntry1 = new DefEntry<>("hello") ;
DefEntry<Long> defEntry2 = new DefEntry<>(999L) ;
// Always True
System.out.println(defEntry1.getClass()==defEntry2.getClass());
}
}
class DefEntry<T> {
private T param ;
public DefEntry (T param){
this.param = param ;
}
}

During compilation , Will check the validity of generics , Verify the successful compilation of class The file has no generic information , That is, generic erasure , View the compiled file with a simple command :

javap -v Generic03.class

Of course, it also brings security problems :

public static void main(String[] args) throws Exception {
Map<String, String> map = new HashMap<>();
Method method = HashMap.class.getDeclaredMethod("put",
new Class[] { Object.class, Object.class });
method.invoke(map,888L, 999L);
// {888=999}
System.out.println(map);
// java.lang.ClassCastException
System.out.println(map.get(888L));
}

Here is the mechanism of reflection , Bypass generics , stay map Put the illegal value type in the program semantics , The type conversion exception is thrown only when the value is obtained in the running process .

Two 、 The reflex mechanism

1、 Basic description

The reflection mechanism can get the complete structure information of the class when the program is running , And it can operate properties and methods dynamically .

Understanding the mechanism of reflection , You have to compile and JVM load , The runtime data area has a clear understanding , This content can be moved JVM Series of articles .

Get the structure of the class dynamically through the runtime , Then dynamically create objects and manipulate properties and methods , This method is not often used in actual development , This obviously consumes JVM resources , And will ignore some of the encapsulation that leads to security issues , This is up there 【1】 This is illustrated by a case in .

2、 Class library of reflection

  • java.lang.Class:Class class
  • java.lang.reflect.Constructor: Constructors
  • java.lang.reflect.Field: attribute
  • java.lang.reflect.Method: Method

API And Class object

Gets the… Of the target type Class Object common ways , adopt Class Object to get the relevant structure information , To operate or access :

public static void main(String[] args) throws Exception {
// Class The object goes back
User user1 = new User(1,"name01") ;
Class userClass1 = user1.getClass() ;
Class userClass2 = Class.forName("com.java.reflect.User");
Class userClass3 = User.class ;
System.out.println(User.class.getName());
System.out.println("userClass1==userClass2?"+(userClass1==userClass2));
System.out.println("userClass2==userClass3?"+(userClass2==userClass3));
// Type creation and judgment
Object object = User.class.newInstance() ;
System.out.println(" type :"+(object instanceof User));
System.out.println(" type :"+(userClass3.isInstance(user1)));
}

Output results :

Here’s a caveat : adopt Class Object’s newInstance() Method , That is, based on User Class , First of all, ask User Class has a parameterless construction method .

API And Constructor Constructors

Class Object read constructor , All construction methods can be obtained separately , Construction methods of different decoration types , Or according to the construction parameter type :

public static void main(String[] args) throws Exception {
Class userClass = User.class ;
// Read public constructor
Constructor[] userConArr = userClass.getConstructors();
printCon(userConArr);
// Read the specified private constructor
Constructor privateCon = userClass.getDeclaredConstructor(Integer.class);
System.out.println(privateCon);
// Read all construction methods
userConArr = userClass.getDeclaredConstructors();
printCon(userConArr);
// Call the public constructor to create the object
Constructor pubCon = userClass.getConstructor(Integer.class,String.class);
Object pubUser = pubCon.newInstance(1,"hello") ;
// Call a private constructor to create an object
Constructor priCon = userClass.getDeclaredConstructor(Integer.class);
// Ignore private Permission modifier
priCon.setAccessible(Boolean.TRUE);
Object priUser = priCon.newInstance(2) ;
System.out.println(pubUser+"\n"+priUser);
}
public static void printCon (Constructor[] constructors){
for (Constructor constructor:constructors){
System.out.println(constructor);
}
}

What needs to be noted here is , By calling setAccessible(Boolean.TRUE) Method , You can create objects based on private construction methods , There’s a clear violation of Java The basic design principles of , Breaking code security .

API And Field attribute

Field Guarantee the properties of member variables , Modifier , Value management and other related operations :

public static void main(String[] args) throws Exception {
Class userClass = User.class ;
// Get public fields
Field[] pubArr = userClass.getFields() ;
printField(pubArr);
// Get all the fields
Field[] fieldArr = userClass.getDeclaredFields() ;
printField(fieldArr);
// Get the specified field
Field emailField = userClass.getField("email") ;
Field nameField = userClass.getDeclaredField("name") ;
printField(new Field[]{emailField,nameField});
// Create objects and manipulate properties
Object userObj = userClass.newInstance() ;
nameField.setAccessible(Boolean.TRUE);
nameField.set(userObj,"world");
emailField.set(userObj,"[email protected]");
System.out.println("userObj:"+userObj);
}
/**
* Print member variable information
*/
public static void printField (Field[] fields){
for (Field field : fields){
System.out.println(" Statement :"+field);
UserAnno userAnno = field.getAnnotation(UserAnno.class) ;
System.out.println(" annotation :"+userAnno.desc());
String fieldName = field.getName() ;
System.out.println(" name :"+fieldName);
Type type = field.getGenericType() ;
System.out.println(" type :"+type);
}
}

Pay attention to get Type Type information , It’s very useful in some specific business scenarios .

API And Method Method

public static void main(String[] args) throws Exception {
Class userClass = User.class ;
// Access to all public methods [ Include parent and Object Class method ]
Method[] pubMethods = userClass.getMethods() ;
printMethod(pubMethods);
// Get all the methods
Method[] allMethods = userClass.getDeclaredMethods() ;
printMethod(allMethods);
// Get the specified method
Method method = userClass.getMethod("parName",String.class) ;
printMethod(new Method[]{method});
// Calling method
Object userObj = userClass.newInstance() ;
Method setId = userClass.getDeclaredMethod("setId", Integer.class);
setId.invoke(userObj,99) ;
Method setName = userClass.getDeclaredMethod("setName", String.class);
setName.invoke(userObj,"java") ;
Method sayHi = userClass.getDeclaredMethod("sayHi", String.class);
sayHi.setAccessible(Boolean.TRUE);
sayHi.invoke(userObj,"c++");
System.out.println(userObj);
}
/**
* Print method information
*/
public static void printMethod (Method[] methods){
for (Method method : methods){
System.out.println(" Definition :"+method);
System.out.println(" name :"+method.getName());
UserAnno userAnno = method.getAnnotation(UserAnno.class) ;
if (userAnno != null){
System.out.println(" annotation :"+userAnno.desc());
}
Type[] paramTypeArr = method.getParameterTypes();
for (int i=0 ; i< paramTypeArr.length; i++){
System.out.print(" Parameters "+(i+1)+" type :"+paramTypeArr[i]+" ; ");
}
System.out.println(" Number of parameters :"+method.getParameterCount());
}
}

Note that the acquisition of methods here is much more than the definition of the class itself , Including inherited from the parent class , and Java Basics Object Class .

3、 … and 、 Source code address

GitHub· Address
https://github.com/cicadasmile/java-base-parent
GitEE· Address
https://gitee.com/cicadasmile/java-base-parent

Read the label

【Java Basics 】【 Design patterns 】【 Structure and algorithm 】【Linux System 】【 database 】

【 Distributed architecture 】【 Microservices 】【 Big data components 】【SpringBoot Advanced 】【Spring&Boot Basics 】

【 Data analysis 】【 Technology map 】【 In the workplace 】

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注