Java Reflection Tutorial for Classes, Methods, Fields, Constructors, Annotations and much more_reports all fields methods 哦日期classes,found in the-程序员宅基地

技术标签: java  Java Reflection  

Reflection in java provides ability to inspect and modify the runtime behavior of applications. Reflection is one of the advance topic of core java. Using reflection we can inspect a class,interfaceenums, get their structure, methods and fields information at runtime even though class is not accessible at compile time. We can also use reflection to instantiate an object, invoke it’s methods, change field values.

  1. Reflection in Java
  2. Reflection for Classes
  3. Reflection for Fields
  4. Reflection for Methods
  5. Reflection for Constructors
  6. Reflection for Annotations

java-reflection-tutorial

Reflection in Java

Reflection is a very powerful concept and it’s of little use in normal programming but it’s the backbone for most of the Java, J2EE frameworks. Some of the frameworks that use reflection are:

  1. JUnit – uses reflection to parse @Test annotation to get the test methods and then invoke it.
  2. Spring – dependency injection, read more at Spring Dependency Injection
  3. Tomcat web container to forward the request to correct module by parsing their web.xml files and request URI.
  4. Eclipse auto completion of method names
  5. Struts
  6. Hibernate

The list is endless and they all use reflection because all these frameworks have no knowledge and access of user defined classes, interfaces, their methods etc.

We should not use reflection in normal programming where we already have access to the classes and interfaces because of following drawbacks.

  • Poor Performance – Since reflection resolve the types dynamically, it involves processing like scanning the classpath to find the class to load, causing slow performance.
  • Security Restrictions – Reflection requires runtime permissions that might not be available for system running under security manager. This can cause you application to fail at runtime because of security manager.
  • Security Issues – Using reflection we can access part of code that we are not supposed to access, for example we can access private fields of a class and change it’s value. This can be a serious security threat and cause your application to behave abnormally.
  • High Maintenance – Reflection code is hard to understand and debug, also any issues with the code can’t be found at compile time because the classes might not be available, making it less flexible and hard to maintain.

Reflection for Classes

In java, every object is either a primitive type or reference. All the classes, enums, arrays are reference types and inherit from java.lang.Object. Primitive types are – boolean, byte, short, int, long, char, float, and double.

java.lang.Class is the entry point for all the reflection operations. For every type of object, JVMinstantiates an immutable instance of java.lang.Class that provides methods to examine the runtime properties of the object and create new objects, invoke its method and get/set object fields.

In this section, we will look into important methods of Class, for convenience, I am creating some classes and interfaces with inheritance hierarchy.

package com.journaldev.reflection;

public interface BaseInterface {
	
	public int interfaceInt=0;
	
	void method1();
	
	int method2(String str);
}
package com.journaldev.reflection;

public class BaseClass {

	public int baseInt;
	
	private static void method3(){
		System.out.println("Method3");
	}
	
	public int method4(){
		System.out.println("Method4");
		return 0;
	}
	
	public static int method5(){
		System.out.println("Method5");
		return 0;
	}
	
	void method6(){
		System.out.println("Method6");
	}
	
	// inner public class
	public class BaseClassInnerClass{}
		
	//member public enum
	public enum BaseClassMemberEnum{}
}
package com.journaldev.reflection;

@Deprecated
public class ConcreteClass extends BaseClass implements BaseInterface {

	public int publicInt;
	private String privateString="private string";
	protected boolean protectedBoolean;
	Object defaultObject;
	
	public ConcreteClass(int i){
		this.publicInt=i;
	}

	@Override
	public void method1() {
		System.out.println("Method1 impl.");
	}

	@Override
	public int method2(String str) {
		System.out.println("Method2 impl.");
		return 0;
	}
	
	@Override
	public int method4(){
		System.out.println("Method4 overriden.");
		return 0;
	}
	
	public int method5(int i){
		System.out.println("Method4 overriden.");
		return 0;
	}
	
	// inner classes
	public class ConcreteClassPublicClass{}
	private class ConcreteClassPrivateClass{}
	protected class ConcreteClassProtectedClass{}
	class ConcreteClassDefaultClass{}
	
	//member enum
	enum ConcreteClassDefaultEnum{}
	public enum ConcreteClassPublicEnum{}
	
	//member interface
	public interface ConcreteClassPublicInterface{}

}

Let’s look at some of the important refection methods for classes.

Get Class Object

We can get Class of an object using three methods – through static variable class, usinggetClass() method of object and java.lang.Class.forName(String fullyClassifiedClassName). For primitive types and arrays, we can use static variable class. Wrapper classes provide another static variable TYPE to get the class.

		// Get Class using reflection
		Class<?> concreteClass = ConcreteClass.class;
		concreteClass = new ConcreteClass(5).getClass();
		try {
			// below method is used most of the times in frameworks like JUnit
			//Spring dependency injection, Tomcat web container
			//Eclipse auto completion of method names, hibernate, Struts2 etc.
			//because ConcreteClass is not available at compile time
			concreteClass = Class.forName("com.journaldev.reflection.ConcreteClass");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		System.out.println(concreteClass.getCanonicalName()); // prints com.journaldev.reflection.ConcreteClass
		
		//for primitive types, wrapper classes and arrays
		Class<?> booleanClass = boolean.class;
		System.out.println(booleanClass.getCanonicalName()); // prints boolean
		
		Class<?> cDouble = Double.TYPE;
		System.out.println(cDouble.getCanonicalName()); // prints double
		
		Class<?> cDoubleArray = Class.forName("[D");
		System.out.println(cDoubleArray.getCanonicalName()); //prints double[]
		
		Class<?> twoDStringArray = String[][].class;
		System.out.println(twoDStringArray.getCanonicalName()); // prints java.lang.String[][]

getCanonicalName() returns the canonical name of the underlying class. Notice that java.lang.Class uses Generics, it helps frameworks in making sure that the Class retrieved is subclass of framework Base Class. Check out Java Generics Tutorial to learn about generics and its wildcards.

Get Super Class

getSuperclass() method on a Class object returns the super class of the class. If this Class represents either the Object class, an interface, a primitive type, or void, then null is returned. If this object represents an array class then the Class object representing the Object class is returned.

		Class<?> superClass = Class.forName("com.journaldev.reflection.ConcreteClass").getSuperclass();
		System.out.println(superClass); // prints "class com.journaldev.reflection.BaseClass"
		System.out.println(Object.class.getSuperclass()); // prints "null"
		System.out.println(String[][].class.getSuperclass());// prints "class java.lang.Object"

Get Public Member Classes

getClasses() method of a Class representation of object returns an array containing Class objects representing all the public classes, interfaces and enums that are members of the class represented by this Class object. This includes public class and interface members inherited from superclasses and public class and interface members declared by the class. This method returns an array of length 0 if this Class object has no public member classes or interfaces or if this Class object represents a primitive type, an array class, or void.

		Class<?>[] classes = concreteClass.getClasses();
		//[class com.journaldev.reflection.ConcreteClass$ConcreteClassPublicClass, 
		//class com.journaldev.reflection.ConcreteClass$ConcreteClassPublicEnum, 
		//interface com.journaldev.reflection.ConcreteClass$ConcreteClassPublicInterface,
		//class com.journaldev.reflection.BaseClass$BaseClassInnerClass, 
		//class com.journaldev.reflection.BaseClass$BaseClassMemberEnum]
		System.out.println(Arrays.toString(classes));

Get Declared Classes

getDeclaredClasses() method returns an array of Class objects reflecting all the classes and interfaces declared as members of the class represented by this Class object. The returned array doesn’t include classes declared in inherited classes and interfaces.

		//getting all of the classes, interfaces, and enums that are explicitly declared in ConcreteClass
		Class<?>[] explicitClasses = Class.forName("com.journaldev.reflection.ConcreteClass").getDeclaredClasses();
		//prints [class com.journaldev.reflection.ConcreteClass$ConcreteClassDefaultClass, 
		//class com.journaldev.reflection.ConcreteClass$ConcreteClassDefaultEnum, 
		//class com.journaldev.reflection.ConcreteClass$ConcreteClassPrivateClass, 
		//class com.journaldev.reflection.ConcreteClass$ConcreteClassProtectedClass, 
		//class com.journaldev.reflection.ConcreteClass$ConcreteClassPublicClass, 
		//class com.journaldev.reflection.ConcreteClass$ConcreteClassPublicEnum, 
		//interface com.journaldev.reflection.ConcreteClass$ConcreteClassPublicInterface]
		System.out.println(Arrays.toString(explicitClasses));

Get Declaring Class

getDeclaringClass() method returns the Class object representing the class in which it was declared.

		Class<?> innerClass = Class.forName("com.journaldev.reflection.ConcreteClass$ConcreteClassDefaultClass");
		//prints com.journaldev.reflection.ConcreteClass
		System.out.println(innerClass.getDeclaringClass().getCanonicalName());
		System.out.println(innerClass.getEnclosingClass().getCanonicalName());

Getting Package Name

getPackage() method returns the package for this class. The class loader of this class is used to find the package. We can invoke getName() method of Package to get the name of the package.

		//prints "com.journaldev.reflection"
		System.out.println(Class.forName("com.journaldev.reflection.BaseInterface").getPackage().getName());

Getting Class Modifiers

getModifiers() method returns the int representation of the class modifiers, we can usejava.lang.reflect.Modifier.toString() method to get it in the string format as used in source code.

		System.out.println(Modifier.toString(concreteClass.getModifiers())); //prints "public"
		//prints "public abstract interface"
		System.out.println(Modifier.toString(Class.forName("com.journaldev.reflection.BaseInterface").getModifiers())); 

Get Type Parameters

getTypeParameters() returns the array of TypeVariable if there are any Type parameters associated with the class. The type parameters are returned in the same order as declared.

		//Get Type parameters (generics)
		TypeVariable<?>[] typeParameters = Class.forName("java.util.HashMap").getTypeParameters();
		for(TypeVariable<?> t : typeParameters)
		System.out.print(t.getName()+",");

Get Implemented Interfaces

getGenericInterfaces() method returns the array of interfaces implemented by the class with generic type information. We can also use getInterfaces() to get the class representation of all the implemented interfaces.

		Type[] interfaces = Class.forName("java.util.HashMap").getGenericInterfaces();
		//prints "1"
		System.out.println(Arrays.toString(interfaces));
		//prints "[interface java.util.Map, interface java.lang.Cloneable, interface java.io.Serializable]"
		System.out.println(Arrays.toString(Class.forName("java.util.HashMap").getInterfaces()));
		

Get All Public Methods

getMethods() method returns the array of public methods of the Class including public methods of it’s superclasses and super interfaces.

		Method[] publicMethods = Class.forName("com.journaldev.reflection.ConcreteClass").getMethods();
		//prints public methods of ConcreteClass, BaseClass, Object
		System.out.println(Arrays.toString(publicMethods));

Get All Public Constructors

getConstructors() method returns the list of public constructors of the class reference of object.

		//Get All public constructors
		Constructor<?>[] publicConstructors = Class.forName("com.journaldev.reflection.ConcreteClass").getConstructors();
		//prints public constructors of ConcreteClass
		System.out.println(Arrays.toString(publicConstructors));

Get All Public Fields

getFields() method returns the array of public fields of the class including public fields of it’s super classes and super interfaces.

		//Get All public fields
		Field[] publicFields = Class.forName("com.journaldev.reflection.ConcreteClass").getFields();
		//prints public fields of ConcreteClass, it's superclass and super interfaces
		System.out.println(Arrays.toString(publicFields));

Get All Annotations

getAnnotations() method returns all the annotations for the element, we can use it with class, fields and methods also. Note that only annotations available with reflection are with retention policy of RUNTIME, check out Java Annotations Tutorial.
We will look into this in more details in later sections.

java.lang.annotation.Annotation[] annotations = Class.forName("com.journaldev.reflection.ConcreteClass").getAnnotations();
//prints [@java.lang.Deprecated()]
System.out.println(Arrays.toString(annotations));

Reflection for Fields

Reflection API provides several methods to analyze Class fields and modify their values at runtime, in this section we will look into some of the commonly used reflection functions for methods.

Get Public Field

In last section, we saw how to get the list of all the public fields of a class. Reflection API also provides method to get specific public field of a class through getField() method. This method look for the field in the specified class reference and then in the super interfaces and then in the super classes.

Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("interfaceInt");

Above call will return the field from BaseInterface that is implemented by ConcreteClass. If there is no field found then it throws NoSuchFieldException.

Field Declaring Class

We can use getDeclaringClass() of field object to get the class declaring the field.

		try {
			Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("interfaceInt");
			Class<?> fieldClass = field.getDeclaringClass();
			System.out.println(fieldClass.getCanonicalName()); //prints com.journaldev.reflection.BaseInterface
		} catch (NoSuchFieldException | SecurityException e) {
			e.printStackTrace();
		}

Get Field Type

getType() method returns the Class object for the declared field type, if field is primitive type, it returns the wrapper class object.

		Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("publicInt");
		Class<?> fieldType = field.getType();
		System.out.println(fieldType.getCanonicalName()); //prints int
			

Get/Set Public Field Value

We can get and set the value of a field in an Object using reflection.

			Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("publicInt");
			ConcreteClass obj = new ConcreteClass(5);
			System.out.println(field.get(obj)); //prints 5
			field.setInt(obj, 10); //setting field value to 10 in object
			System.out.println(field.get(obj)); //prints 10

get() method return Object, so if field is primitive type, it returns the corresponsing Wrapper Class. If the field is static, we can pass Object as null in get() method.

There are several set*() methods to set Object to the field or set different types of primitive types to the field. We can get the type of field and then invoke correct function to set the field value correctly. If the field is final, the set() methods throw java.lang.IllegalAccessException.

Get/Set Private Field Value

We know that private fields and methods can’t be accessible outside of the class but using reflection we can get/set the private field value by turning off the java access check for field modifiers.

	Field privateField = Class.forName("com.journaldev.reflection.ConcreteClass").getDeclaredField("privateString");
	//turning off access check with below method call
	privateField.setAccessible(true);
	ConcreteClass objTest = new ConcreteClass(1);
	System.out.println(privateField.get(objTest)); // prints "private string"
	privateField.set(objTest, "private string updated");
	System.out.println(privateField.get(objTest)); //prints "private string updated"

Reflection for Methods

Using reflection we can get information about a method and we can invoke it also. In this section, we will learn different ways to get a method, invoke a method and accessing private methods.

Get Public Method

We can use getMethod() to get a public method of class, we need to pass the method name and parameter types of the method. If the method is not found in the class, reflection API looks for the method in superclass.

In below example, I am getting put() method of HashMap using reflection. The example also shows how to get the parameter types, method modifiers and return type of a method.

Method method = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class);
//get method parameter types, prints "[class java.lang.Object, class java.lang.Object]"
System.out.println(Arrays.toString(method.getParameterTypes()));
//get method return type, return "class java.lang.Object", class reference for void
System.out.println(method.getReturnType());
//get method modifiers
System.out.println(Modifier.toString(method.getModifiers())); //prints "public"

Invoking Public Method

We can use invoke() method of Method object to invoke a method, in below example code I am invoking put method on HashMap using reflection.

Method method = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class);
Map<String, String> hm = new HashMap<>();
method.invoke(hm, "key", "value");
System.out.println(hm); // prints {key=value}

If the method is static, we can pass NULL as object argument.

Invoking Private Methods

We can use getDeclaredMethod() to get the private method and then turn off the access check to invoke it, below example shows how we can invoke method3() of BaseClass that is static and have no parameters.

		//invoking private method
		Method method = Class.forName("com.journaldev.reflection.BaseClass").getDeclaredMethod("method3", null);
		method.setAccessible(true);
		method.invoke(null, null); //prints "Method3"

Reflection for Constructors

Reflection API provides methods to get the constructors of a class to analyze and we can create new instances of class by invoking the constructor. We have already learned how to get all the public constructors.

Get Public Constructor

We can use getConstructor() method on the class representation of object to get specific public constructor. Below example shows how to get the constructor of ConcreteClass defined above and the no-argument constructor of HashMap. It also shows how to get the array of parameter types for the constructor.

		Constructor<?> constructor = Class.forName("com.journaldev.reflection.ConcreteClass").getConstructor(int.class);
		//getting constructor parameters
		System.out.println(Arrays.toString(constructor.getParameterTypes())); // prints "[int]"
		
		Constructor<?> hashMapConstructor = Class.forName("java.util.HashMap").getConstructor(null);
		System.out.println(Arrays.toString(hashMapConstructor.getParameterTypes())); // prints "[]"

Instantiate Object using Constructor

We can use newInstance() method on the constructor object to instantiate a new instance of the class. Since we use reflection when we don’t have the classes information at compile time, we can assign it to Object and then further use reflection to access it’s fields and invoke it’s methods.

		Constructor<?> constructor = Class.forName("com.journaldev.reflection.ConcreteClass").getConstructor(int.class);
		//getting constructor parameters
		System.out.println(Arrays.toString(constructor.getParameterTypes())); // prints "[int]"
		
		Object myObj = constructor.newInstance(10);
		Method myObjMethod = myObj.getClass().getMethod("method1", null);
		myObjMethod.invoke(myObj, null); //prints "Method1 impl."

		Constructor<?> hashMapConstructor = Class.forName("java.util.HashMap").getConstructor(null);
		System.out.println(Arrays.toString(hashMapConstructor.getParameterTypes())); // prints "[]"
		HashMap<String,String> myMap = (HashMap<String,String>) hashMapConstructor.newInstance(null);

Reflection for Annotations

Annotations was introduced in Java 1.5 to provide metadata information of the class, methods or fields and now it’s heavily used in frameworks like Spring and Hibernate. Reflection API was also extended to provide support to analyze the annotations at runtime.

Using reflection API we can analyze annotations whose retention policy is Runtime. I have already written a detailed tutorial on annotations and how we can use reflection API to parse annotations, so I would suggest you to check out Java Annotations Tutorial.

Thats all for reflection in java, I hope you liked the tutorial and understood the importance of Java Reflection API.

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/doctor_who2004/article/details/42196723

智能推荐

使用nginx解决浏览器跨域问题_nginx不停的xhr-程序员宅基地

文章浏览阅读1k次。通过使用ajax方法跨域请求是浏览器所不允许的,浏览器出于安全考虑是禁止的。警告信息如下:不过jQuery对跨域问题也有解决方案,使用jsonp的方式解决,方法如下:$.ajax({ async:false, url: 'http://www.mysite.com/demo.do', // 跨域URL ty..._nginx不停的xhr

在 Oracle 中配置 extproc 以访问 ST_Geometry-程序员宅基地

文章浏览阅读2k次。关于在 Oracle 中配置 extproc 以访问 ST_Geometry,也就是我们所说的 使用空间SQL 的方法,官方文档链接如下。http://desktop.arcgis.com/zh-cn/arcmap/latest/manage-data/gdbs-in-oracle/configure-oracle-extproc.htm其实简单总结一下,主要就分为以下几个步骤。..._extproc

Linux C++ gbk转为utf-8_linux c++ gbk->utf8-程序员宅基地

文章浏览阅读1.5w次。linux下没有上面的两个函数,需要使用函数 mbstowcs和wcstombsmbstowcs将多字节编码转换为宽字节编码wcstombs将宽字节编码转换为多字节编码这两个函数,转换过程中受到系统编码类型的影响,需要通过设置来设定转换前和转换后的编码类型。通过函数setlocale进行系统编码的设置。linux下输入命名locale -a查看系统支持的编码_linux c++ gbk->utf8

IMP-00009: 导出文件异常结束-程序员宅基地

文章浏览阅读750次。今天准备从生产库向测试库进行数据导入,结果在imp导入的时候遇到“ IMP-00009:导出文件异常结束” 错误,google一下,发现可能有如下原因导致imp的数据太大,没有写buffer和commit两个数据库字符集不同从低版本exp的dmp文件,向高版本imp导出的dmp文件出错传输dmp文件时,文件损坏解决办法:imp时指定..._imp-00009导出文件异常结束

python程序员需要深入掌握的技能_Python用数据说明程序员需要掌握的技能-程序员宅基地

文章浏览阅读143次。当下是一个大数据的时代,各个行业都离不开数据的支持。因此,网络爬虫就应运而生。网络爬虫当下最为火热的是Python,Python开发爬虫相对简单,而且功能库相当完善,力压众多开发语言。本次教程我们爬取前程无忧的招聘信息来分析Python程序员需要掌握那些编程技术。首先在谷歌浏览器打开前程无忧的首页,按F12打开浏览器的开发者工具。浏览器开发者工具是用于捕捉网站的请求信息,通过分析请求信息可以了解请..._初级python程序员能力要求

Spring @Service生成bean名称的规则(当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致)_@service beanname-程序员宅基地

文章浏览阅读7.6k次,点赞2次,收藏6次。@Service标注的bean,类名:ABDemoService查看源码后发现,原来是经过一个特殊处理:当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致public class AnnotationBeanNameGenerator implements BeanNameGenerator { private static final String C..._@service beanname

随便推点

二叉树的各种创建方法_二叉树的建立-程序员宅基地

文章浏览阅读6.9w次,点赞73次,收藏463次。1.前序创建#include&lt;stdio.h&gt;#include&lt;string.h&gt;#include&lt;stdlib.h&gt;#include&lt;malloc.h&gt;#include&lt;iostream&gt;#include&lt;stack&gt;#include&lt;queue&gt;using namespace std;typed_二叉树的建立

解决asp.net导出excel时中文文件名乱码_asp.net utf8 导出中文字符乱码-程序员宅基地

文章浏览阅读7.1k次。在Asp.net上使用Excel导出功能,如果文件名出现中文,便会以乱码视之。 解决方法: fileName = HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8);_asp.net utf8 导出中文字符乱码

笔记-编译原理-实验一-词法分析器设计_对pl/0作以下修改扩充。增加单词-程序员宅基地

文章浏览阅读2.1k次,点赞4次,收藏23次。第一次实验 词法分析实验报告设计思想词法分析的主要任务是根据文法的词汇表以及对应约定的编码进行一定的识别,找出文件中所有的合法的单词,并给出一定的信息作为最后的结果,用于后续语法分析程序的使用;本实验针对 PL/0 语言 的文法、词汇表编写一个词法分析程序,对于每个单词根据词汇表输出: (单词种类, 单词的值) 二元对。词汇表:种别编码单词符号助记符0beginb..._对pl/0作以下修改扩充。增加单词

android adb shell 权限,android adb shell权限被拒绝-程序员宅基地

文章浏览阅读773次。我在使用adb.exe时遇到了麻烦.我想使用与bash相同的adb.exe shell提示符,所以我决定更改默认的bash二进制文件(当然二进制文件是交叉编译的,一切都很完美)更改bash二进制文件遵循以下顺序> adb remount> adb push bash / system / bin /> adb shell> cd / system / bin> chm..._adb shell mv 权限

投影仪-相机标定_相机-投影仪标定-程序员宅基地

文章浏览阅读6.8k次,点赞12次,收藏125次。1. 单目相机标定引言相机标定已经研究多年,标定的算法可以分为基于摄影测量的标定和自标定。其中,应用最为广泛的还是张正友标定法。这是一种简单灵活、高鲁棒性、低成本的相机标定算法。仅需要一台相机和一块平面标定板构建相机标定系统,在标定过程中,相机拍摄多个角度下(至少两个角度,推荐10~20个角度)的标定板图像(相机和标定板都可以移动),即可对相机的内外参数进行标定。下面介绍张氏标定法(以下也这么称呼)的原理。原理相机模型和单应矩阵相机标定,就是对相机的内外参数进行计算的过程,从而得到物体到图像的投影_相机-投影仪标定

Wayland架构、渲染、硬件支持-程序员宅基地

文章浏览阅读2.2k次。文章目录Wayland 架构Wayland 渲染Wayland的 硬件支持简 述: 翻译一篇关于和 wayland 有关的技术文章, 其英文标题为Wayland Architecture .Wayland 架构若是想要更好的理解 Wayland 架构及其与 X (X11 or X Window System) 结构;一种很好的方法是将事件从输入设备就开始跟踪, 查看期间所有的屏幕上出现的变化。这就是我们现在对 X 的理解。 内核是从一个输入设备中获取一个事件,并通过 evdev 输入_wayland

推荐文章

热门文章

相关标签