Java反射(3万字总结,最后的最后我想要一个赞,您的支持是我的动力)

导读:本篇文章讲解 Java反射(3万字总结,最后的最后我想要一个赞,您的支持是我的动力),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

文章目录

前言

一直对于反射很感兴趣,原本以为要到框架才能接触到,但往往计划没有变化快,今天终于接触到了心心念念的——反射了。year…
在这里插入图片描述

一、关于反射与注解的那些话(了解)

近十几年来,在Java和Android开发领域中涌现出许多优秀的框架,比如:Spring、Hibernate、Mybatis、Retrofit、Afinal、OKHttp、ButterKnife等等。这些框架的出现极大地简化了开发流程,提高了工作效率。在项目开发的过程中我们主要是使用这些轮子完成项目,很难有时间去顾及框架的内部实现。

1、反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法。
2、反射可以在一个类运行的时候获取类的信息的机制,可以获取在编译期不可能获得的类的信息。
3、对于任意一个对象,都能调用它的任意一个方法和属性。
4、因为类的信息是保存在Class对象中的,而这个Class对象是在程序运行时被类加载器(ClassLoader)动态加载的。

二、编程语言类型

1.静态类型语言

静态类型语言(Statically Typed Language)也称为强类型语言。在静态语言中,在编译时确定变量的数据类型。所以,绝大多数静态类型语言要求:先声明变量(即确定变量类型)后再使用变量。

常见的静态类型语言有:Java、 C、C++等等

2.动态类型语言

动态类型语言(Dynamic programming Language)也称为弱类型语言。在动态类型语言中,程序在运行时可以改变其结构;例如:改变变量原有的数据类型、新的函数被引进,已有的函数被删除等在结构上的变化。

常见的动态类型语言有:JavaScript、 PHP、Ruby等等。

2.1Java与动态性

Java程序的执行有两个阶段:
1、编译
2、运行
关于Java的编译、运行请参考:Java中字节码及其优势

在编译阶段会检查基本语法是否正确、变量的类型及其使用是否正确。程序在通过编译之后生成与之对应的字节码文件.class。JVM调用代码时,程序处于运行时状态。虽然说Java语言是静态类型语言,但是它在运行时借助反射从而具有了一定的动态性。所以,也有人说Java是”准动态类型语言”。

三、反射

1.反射的定义

Java的反射(Reflection)机制是指在程序运行时动态获取程序信息和动态调用对象的功能。反射是Java实现动态性的关键,其主要作用如下:

1、在运行时判断任意一个对象所属的类
2、在运行时构造任意一个类的对象
3、在运行时判断任意一个类所具有的成员变量和方法
4、在运行时调用任意一个对象的成员变量和方法
5、在运行时获取泛型信息
6、在运行时处理注解
7、在运行时生成动态代理

2.反射的应用场景

1、插件化编程
2、服务端编程
3、无.java源文件
4、获取类的所有信息
5、调用私有属性和方法

3.关于反射学习的进程的科学安排

1、ClassLoader
2、Class
3、Reflection API
在这里插入图片描述

四、类加载器

1.类加载器的分类

Java的类加载器有如下四种:

1、启动类加载器(Bootstrap Classloader)
2、扩展类加载器(Extension ClassLoader)
3、应用程序类加载器(Application Classloader)
4、自定义类加载器(User Classloader)

关于Java类加载器的关系请参考:Java类加载器

1.1启动类加载器(Bootstrap Classloader)

启动类加载器(Bootstrap Classloader)并不是java.lang.ClassLoder的子类,而是使用C/C++实现的。所以,无法通过Java代码获取启动类加载器。

代码如下(获取启动类加载器(Bootstrap Classloader) 代码演示):

public class GetBootstrapClassloader {

	public static void main(String[] args) {
		String string = "hello 反射!";
		Class<? extends String> clazz = string.getClass();
		ClassLoader classLoader = clazz.getClassLoader();
		System.out.println(classLoader);
	}
}

代码如下(获取启动类加载器(Bootstrap Classloader) 输出):

null

1.2扩展类加载器(Extension ClassLoader)

扩展类加载器(Extension ClassLoader)由sun.misc.Launcher$ExtClassLoader实现,它是java.lang.ClassLoader的子类。该类加载器负责加载Java的扩展库JAVA_HOME/jre/lib/ext/*.jar或者java.ext.dirs路径下的内容。
代码如下(获取扩展类加载器(Extension ClassLoader) 代码演示):

import java.io.File;
import java.util.StringTokenizer;

public class GetExtensionClassLoader {

	public static void main(String[] args) {
		String string = System.getProperty("java.ext.dirs");
		StringTokenizer stringTokenizer = new StringTokenizer(string, File.pathSeparator);
		int countTokens = stringTokenizer.countTokens();
		File[] extDirs = new File[countTokens];
		for(int i = 0;i<countTokens;i++) {
			String nextToken = stringTokenizer.nextToken();
			extDirs[i] = new File(nextToken);
			System.out.println(extDirs[i]);
		}
	}
}

代码如下(获取启动类加载器(Bootstrap Classloader) 输出):

C:\Program Files\Java\jdk1.8.0_162\jre\lib\ext
C:\Windows\Sun\Java\lib\ext

1.3应用程序类加载器(Application Classloader)

应用程序类加载器(Application Classloader)由sun.misc.Launcher$AppClassLoader实现,它是java.lang.ClassLoader的子类。该类加载器负责加载Java应用程序类路径classpath或者java.class.path下的内容。也就是说:平常,我们在项目中自己写的类就是由应用程序类加载器加载进内存的。

代码如下(获取应用程序类加载器(Application Classloader) 代码演示):

public class GetApplicationClassLoader {

	public static void main(String[] args) throws Exception {
		Class<?> clazz = Class.forName("com.classloader.Student");
		ClassLoader classLoader = clazz.getClassLoader();
		System.out.println(classLoader);

	}
}

代码如下(获取应用程序类加载器(Application Classloader) 输出):

sun.misc.Launcher$AppClassLoader@6d06d69c

五、Class类

类加载器将类的.class文件加载进内存之后会在堆内存的方法区中产生Class类型的对象;该对象包含了类的所有结构信息。一个类有且只有一个Class对象,相同的类具有相同的Class对象 。我们只要获得了Class对象,就可以全面剖析一个类并可创建该类的对象且调用其方法。

1.在运行时类和接口对应的Class对象

代码如下(在运行时类和接口对应的Class对象 代码演示):

public class GetClass {
	public static void main(String[] args) {
		// 获取String类对应的class对象
		Class<String> clazz01 = String.class;
		// 获取Thread接口对应的class对象
		Class<Thread> clazz02 = Thread.class;
		System.out.println(clazz01);
		System.out.println(clazz02);
	}

}

代码如下(在运行时类和接口对应的Class对象 输出):

class java.lang.String
class java.lang.Thread

2.在运行时枚举和注释(即注解)也存在Class对象

代码如下(在运行时枚举和注释对应的Class对象 代码演示):

import java.lang.annotation.ElementType;

public class GetClass {
	public static void main(String[] args) {
		// 获取ElementType枚举对应的class对象
		Class<?> clazz01 = ElementType.class;
		// 获取Overridezhu注解对应的class对象
		Class<?> clazz02 = Override.class;
		System.out.println(clazz01);
		System.out.println(clazz02);
	}
}

代码如下(在运行时枚举和注释对应的Class对象 输出):

class java.lang.annotation.ElementType
interface java.lang.Override

3.在运行时,数组也存在相应的Class对象

代码如下(在运行时数组对应的Class对象 代码演示):

public class GetClass {
	public static void main(String[] args) {
		// 获取一维数组对应的class对象
		Class<?> clazz01 = int[].class;
		// 获取二维数组对应的class对象
		Class<?> clazz02 = int[][].class;
		System.out.println(clazz01);
		System.out.println(clazz02);
	}
}

代码如下(在运行时枚举和注释对应的Class对象 输出):

class [I
class [[I

4. 在运行时,Java基本数据类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象

代码如下(在运行时,Java基本数据类型关键字 void 也表示为 Class 对象 代码演示):

public class GetClass {
	public static void main(String[] args) {
		// 获取int的class对象
		Class<?> clazz01 = int.class;
		// 获取void对应的class对象
		Class<?> clazz02 = void.class;
		// 获取boolean对应的class对象
		Class<?> clazz03 = boolean.class;
		System.out.println(clazz01);
		System.out.println(clazz02);
		System.out.println(clazz03);
	}
}

代码如下(在运行时,Java基本数据类型关键字 void 也表示为 Class 对象 输出):

int
void
boolean

5. 获取Class对象的方式小结

在这里插入图片描述

5.1 类型名.class

该方式适用于任意类型获取Class对象

代码如下(示例):

	// 通过类型名.class获取class对象
	public static void test01() {
		Class<?> clazz01 = int.class;
		Class<?> clazz02 = String.class;
		System.out.println(clazz01);
		System.out.println(clazz02);
	}

代码如下(输出):

int
class java.lang.String

5.2 引用类型对象.getClass( )

因为只有引用类型才有对象;所以,该方式适用于引用类型获取Class对象

代码如下(示例):

	// 通过引用类型对象.getClass()获取Class对象
	public static void test02() {
		String string = "时间带带";
		Class<? extends String> clazz01 = string.getClass();
		Object object = new Object();
		Class<? extends Object> clazz02 = object.getClass();
		System.out.println(clazz01);
		System.out.println(clazz02);
	}

代码如下(输出):

class java.lang.String
class java.lang.Object

5.3 Class.forName(“类的全限定名”)

该方式适用于除数组以外的引用类型数据获取Class对象

代码如下(示例):

	// 通过Class.forName("类的全限定名")获取Class对象
	public static void test03() {
		Class<?> clazz01;
		try {
			clazz01 = Class.forName("java.lang.String");
			System.out.println(clazz01);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

代码如下(输出):

class java.lang.String

5.4 类加载器对象.loadClass(“类的全限定名”)

该方式适用于除数组以外的引用类型数据获取Class对象。

代码如下(示例):

	public static void test04() throws Exception {
		ClassLoader classLoader = ClassLoader.getSystemClassLoader();
		Class<?> loadClass = classLoader.loadClass("java.lang.String");
		System.out.println(loadClass);
	}

代码如下(输出):

class java.lang.String

六、Reflection API

1. 运行时获取类加载器

在这里插入图片描述

1.1 API

获取类加载器

ClassLoader java.lang.Class.getClassLoader()

1.2 运行时获取类加载器代码演示

代码如下(示例):

public class GetClassLoader {

	public static void main(String[] args) {
		// 获取String类的类加载器
		Class<?> clazz01 = String.class;
		ClassLoader classLoader01 = clazz01.getClassLoader();
		// 获取Test1类的类加载器
		Class<?> clazz02 = Test1.class;
		ClassLoader classLoader02 = clazz02.getClassLoader();
		System.out.println(classLoader01);
		System.out.println(classLoader02);
	}
}

代码如下(输出):

null
sun.misc.Launcher$AppClassLoader@6d06d69c

2. 运行时获取类的全限定名和包名

2.1 API

获取类的全限定名

String java.lang.Class.getName()

如果此类对象表示的是非数组类型的引用类型,则返回包.类名

如果此类对象表示一个基本类型或 void,则返回该基本类型或 void 所对应的 Java 语言关键字相同的字符串

如果此类对象表示一个数组类,则名字的内部形式为:表示该数组嵌套深度的一个或多个 ‘[’ 字符加元素类型名。其中,元素类型名的编码如下:

Element Type Encoding
byte B
short S
int I
long L
float F
double D
boolean Z
char C
class or interface Lclassname

获取类所属包

Package java.lang.Class.getPackage()

获取类所属包的名称

String java.lang.Package.getName()

2.1 运行时获取类的全限定名和包名代码演示

代码如下(示例):

public class GetNameTest {

	public static void main(String[] args) {
		// 获取String类的class对象
		Class<?> clazz01 = String.class;
		// 获取String类的全限定名
		String name = clazz01.getName();
		// 获取String类的包名
		String packageName = clazz01.getPackage().getName();
		System.out.println("全限定名为:"+name);
		System.out.println("包名为:"+packageName);
	}
}

代码如下(输出):

全限定名为:java.lang.String
包名为:java.lang

3. 运行时获取类的修饰

3.1 API

获取类或接口的修饰符

int java.lang.Class.getModifiers()

获取类或接口的修饰符的字符串表示形式

String java.lang.reflect.Modifier.toString(int mod)

判断类或接口是否被public修饰

boolean java.lang.reflect.Modifier.isPublic(int mod)

3.2 运行时获取类的修饰代码演示

代码如下(示例):

import java.lang.reflect.Modifier;

public class Demo {

	public static void main(String[] args) {
		// 获取String类的class对象
		Class<?> clazz01 = String.class;
		// 获取String类的修饰符
		int modifiers = clazz01.getModifiers();
		// 将String类的修饰符转成字符串
		String modifierString = Modifier.toString(modifiers);
		// 判断String类是否被public修饰
		boolean public1 = Modifier.isPublic(modifiers);
		System.out.println(modifierString);
		System.out.println(public1);

	}

}

代码如下(输出):

public final
true

4. 运行时获取类的基本信息

4.1 API

获取类的父类

Class<? super Object> java.lang.Class.getSuperclass()

获取类实现的接口

Class<?>[] java.lang.Class.getInterfaces()

4.2 运行时获取类的基本信息代码演示

代码如下(示例):

import java.lang.reflect.Modifier;

public class Demo {

	public static void main(String[] args) {
		// 获取String类的class对象
		Class<?> clazz01 = String.class;
		// 获取String类的修饰符
		int modifiers = clazz01.getModifiers();
		// 将String类的修饰符转成字符串
		String modifierString = Modifier.toString(modifiers);
		// 判断String类是否被public修饰
		boolean public1 = Modifier.isPublic(modifiers);
		// 获取String类的父类
		Class<?> superclass = clazz01.getSuperclass();
		// 获取String类实现的接口
		Class<?>[] interfaces = clazz01.getInterfaces();
		for(Class<?> c:interfaces) {
			System.out.println("String类实现的接口:"+c);
		}
		System.out.println("String类的父类:"+superclass);
		System.out.println("String类的修饰符:"+modifierString);
		System.out.println("关于String类的修饰是否被public修饰:"+public1);

	}

}

代码如下(输出):

String类实现的接口:interface java.io.Serializable
String类实现的接口:interface java.lang.Comparable
String类实现的接口:interface java.lang.CharSequence
String类的父类:class java.lang.Object
String类的修饰符:public final
关于String类的修饰是否被public修饰:true

5. 运行时获取类的属性

在这里插入图片描述

5.1测试类(自己故意写的为了方便测试)

package com.Student;

public class Student {
	public String name;
	public String gender;
	private int age;
	public Student() {

	}
	public Student(String name, String gender, int age) {
		super();
		this.name = name;
		this.gender = gender;
		this.age = age;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	

}

5.2 API

获取类的所有公共属性

Field[] java.lang.Class.getFields() throws SecurityException

获取类的所有声明属性

Field[] java.lang.Class.getDeclaredFields() throws SecurityException

获取属性的名称

String java.lang.reflect.Field.getName()

获取属性类型

Class<?> java.lang.reflect.Field.getType()

获取属性修饰符

int java.lang.reflect.Field.getModifiers()

是否取消安全性检查

void java.lang.reflect.AccessibleObject.setAccessible(boolean flag) throws SecurityException

5.3 运行时获取类的属性代码演示

代码如下(示例):

package com.Student;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class Test {

	public static void main(String[] args) {
		// 获取自定义的Student类的Class对象
		Class<?> clazz = Student.class;
		// 获取自定义的Student类的公有属性
		Field[] fields1 = clazz.getFields();
		for(Field f:fields1) {
			System.out.println("Student类的公有属性有:"+f);
			// 获取Student类的公有属性的名称
			String name = f.getName();
			// 获取Student类的公有属性的类型
			Class<?> type = f.getType();
			// 获取Student类的公有属性的修饰符
			int modifiers = f.getModifiers();
			String modifierString = Modifier.toString(modifiers);
			System.out.println("Student类的公有属性名称有:"+name);
			System.out.println("Student类的公有属性类型有:"+type);
			System.out.println("Student类的公有属性修饰符有:"+modifierString);
		}
		Field[] fields2 = clazz.getDeclaredFields();
		for(Field f:fields2) {
			System.out.println("Student类的声明属性有:"+f);
			// 获取Student类的声明属性的名称
			String name = f.getName();
			// 获取Student类的声明属性的类型
			Class<?> type = f.getType();
			// 获取Student类的声明属性的修饰符
			int modifiers = f.getModifiers();
			String modifierString = Modifier.toString(modifiers);
			System.out.println("Student类的声明属性名称有:"+name);
			System.out.println("Student类的声明属性类型有:"+type);
			System.out.println("Student类的声明属性修饰符有:"+modifierString);
		}

	}

}

代码如下(输出):

Student类的公有属性有:public java.lang.String com.Student.Student.name
Student类的公有属性名称有:name
Student类的公有属性类型有:class java.lang.String
Student类的公有属性修饰符有:public
Student类的公有属性有:public java.lang.String com.Student.Student.gender
Student类的公有属性名称有:gender
Student类的公有属性类型有:class java.lang.String
Student类的公有属性修饰符有:public
Student类的声明属性有:public java.lang.String com.Student.Student.name
Student类的声明属性名称有:name
Student类的声明属性类型有:class java.lang.String
Student类的声明属性修饰符有:public
Student类的声明属性有:public java.lang.String com.Student.Student.gender
Student类的声明属性名称有:gender
Student类的声明属性类型有:class java.lang.String
Student类的声明属性修饰符有:public
Student类的声明属性有:private int com.Student.Student.age
Student类的声明属性名称有:age
Student类的声明属性类型有:int
Student类的声明属性修饰符有:private

6. 运行时获取类的构造函数

在这里插入图片描述

6.1测试类(自己故意写的,为了方便测试)

public class Student {
	private int age;
	public String name;

	public Student() {
		super();
		// TODO Auto-generated constructor stub
	}

	public Student(int age, String name) {
		super();
		this.age = age;
		this.name = name;
	}

	private Student(String name) {
		super();
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
	
}

6.2 API

获取类的所有的公共构造器

Constructor<?>[] java.lang.Class.getConstructors() throws SecurityException

获取类的所有的声明构造器

Constructor<?>[] java.lang.Class.getDeclaredConstructors() throws SecurityException

获取指定的公共构造器

Constructor<Object> java.lang.Class.getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException

获取指定的声明构造器

Constructor<Object> java.lang.Class.getDeclaredConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException

获取构造器修饰符

int java.lang.reflect.Constructor.getModifiers()

获取构造器形参

Class<?>[] java.lang.reflect.Constructor.getParameterTypes()

6.3 运行时获取类的构造函数代码演示

代码如下(示例):

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

public class Test {

	public static void main(String[] args) {
		// 获取运行时测试类Student对应的class对象
		Class<?> clazz = Student.class;
		// 获取测试类Student所有公共构造器
		Constructor<?>[] constructors = clazz.getConstructors();
		for(Constructor<?> c:constructors) {
			// 获取构造器的名字
			String name = c.getName();
			System.out.println("公共构造器的名字都有"+name);
			// 获取构造器的修饰符
			int modifiers = c.getModifiers();
			String modifierString = Modifier.toString(modifiers);
			System.out.println("公共构造器的修饰符都有"+modifierString);
			// 获取构造器的形参
			Class<?>[] parameterTypes = c.getParameterTypes();
			for(Class<?> p:parameterTypes) {
				System.out.println("公共构造器的形参"+p);
			}
		}
		System.out.println("------------------");
		// 获取测试类Student所有声明(即这个类所有公有私有的构造器)构造器
		Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
		for(Constructor<?> c:declaredConstructors) {
			// 获取构造器的名字
			String name = c.getName();
			System.out.println("声明构造器的名字都有"+name);
			// 获取构造器的修饰符
			int modifiers = c.getModifiers();
			String modifierString = Modifier.toString(modifiers);
			System.out.println("声明构造器的修饰符都有"+modifierString);
			// 获取构造器的形参
			Class<?>[] parameterTypes = c.getParameterTypes();
			for(Class<?> p:parameterTypes) {
				System.out.println("声明构造器的形参"+p);
			}
		}
	}

}

代码如下(输出):

公共构造器的名字都有Student
公共构造器的修饰符都有public
公共构造器的形参int
公共构造器的形参class java.lang.String
公共构造器的名字都有Student
公共构造器的修饰符都有public
------------------
声明构造器的名字都有Student
声明构造器的修饰符都有private
声明构造器的形参class java.lang.String
声明构造器的名字都有Student
声明构造器的修饰符都有public
声明构造器的形参int
声明构造器的形参class java.lang.String
声明构造器的名字都有Student
声明构造器的修饰符都有public

7. 运行时获取类的方法

7.1测试类(自己故意写的,为了方便测试)

import java.util.Date;

public class Student {
	public String name;
	public String gender;
	private int age;
	public Student() {
	}
	public Student(String name, String gender, int age) {
		super();
		this.name = name;
		this.gender = gender;
		this.age = age;
	}
	public int getAge() {
		return age;
	}
	private void setAge(int age) {
		this.age = age;
	}
    private String printInfo(String message) {
        System.out.println("Star中的私有方法printInfo() 输入参数 message="+message);
        String result="最新消息:"+message;
        return result;
    }
	//static修饰的静态方法
	public static void printDate() {
	    System.out.println(new Date());
	}

}

7.2 API

获取该类及其父类的公共方法,但不能获取到私有方法

Method[] java.lang.Class.getMethods() throws SecurityException

获取该类本身所声明的所有方法

Method[] java.lang.Class.getDeclaredMethods() throws SecurityException

获取指定的公共方法

Method java.lang.Class.getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException

获取指定的声明方法

Method java.lang.Class.getDeclaredMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException

获取方法的名称

String java.lang.reflect.Method.getName()

获取方法修饰符

int java.lang.reflect.Method.getModifiers()

获取方法的返回值类型

Class<?> java.lang.reflect.Method.getReturnType()

获取方法的形参

Class<?>[] java.lang.reflect.Method.getParameterTypes()

获取方法抛出的异常

Class<?>[] java.lang.reflect.Method.getExceptionTypes()

7.3 运行时获取类的方法代码演示

7.3.1 获取该类及其父类的公共方法,但不能获取到私有方法

代码如下(示例):

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Test1 {

	public static void main(String[] args) {
		// 获取自定义的Student类的Class对象
		Class<?> clazz = Student.class;
		// 获取自定义的Student及其父类的公共方法,但不能获取到私有方法
		Method[] methods = clazz.getMethods();
		for(Method m:methods) {
			System.out.println("Student及其父类的公共方法:"+m);
			// 获取Student类的方法的名称
			String name = m.getName();
			// 获取方法返回值类型
			Class<?> returnType = m.getReturnType();
			// 获取Student类的方法的修饰符
			int modifiers = m.getModifiers();
			String modifierString = Modifier.toString(modifiers);
			// 获取方法的形参
			Class<?>[] parameterTypes = m.getParameterTypes();
			// 获取方法抛出的异常
			Class<?>[] exceptionTypes = m.getExceptionTypes();
			for(Class<?> exc:exceptionTypes) {
				System.out.println("Student类所有公共方法的异常有:"+exc);
			}
			System.out.println("Student类的公共方法有:"+name);
			System.out.println("Student类的公共方法返回值类型有:"+returnType);
			System.out.println("Student类的公共方法的修饰符有:"+parameterTypes);
			System.out.println("Student类的公共方法的形参有:"+modifierString);
		}
		
	}
}

代码如下(输出):

Student及其父类的公共方法:public int com.etime2.Student.getAge()
Student类的公共方法有:getAge
Student类的公共方法返回值类型有:int
Student类的公共方法的修饰符有:[Ljava.lang.Class;@33909752
Student类的公共方法的形参有:public
Student及其父类的公共方法:public static void com.etime2.Student.printDate()
Student类的公共方法有:printDate
Student类的公共方法返回值类型有:void
Student类的公共方法的修饰符有:[Ljava.lang.Class;@55f96302
Student类的公共方法的形参有:public static
Student及其父类的公共方法:public final void java.lang.Object.wait() throws java.lang.InterruptedException
Student类所有公共方法的异常有:class java.lang.InterruptedException
Student类的公共方法有:wait
Student类的公共方法返回值类型有:void
Student类的公共方法的修饰符有:[Ljava.lang.Class;@3d4eac69
Student类的公共方法的形参有:public final
Student及其父类的公共方法:public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
Student类所有公共方法的异常有:class java.lang.InterruptedException
Student类的公共方法有:wait
Student类的公共方法返回值类型有:void
Student类的公共方法的修饰符有:[Ljava.lang.Class;@42a57993
Student类的公共方法的形参有:public final
Student及其父类的公共方法:public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
Student类所有公共方法的异常有:class java.lang.InterruptedException
Student类的公共方法有:wait
Student类的公共方法返回值类型有:void
Student类的公共方法的修饰符有:[Ljava.lang.Class;@75b84c92
Student类的公共方法的形参有:public final native
Student及其父类的公共方法:public boolean java.lang.Object.equals(java.lang.Object)
Student类的公共方法有:equals
Student类的公共方法返回值类型有:boolean
Student类的公共方法的修饰符有:[Ljava.lang.Class;@6bc7c054
Student类的公共方法的形参有:public
Student及其父类的公共方法:public java.lang.String java.lang.Object.toString()
Student类的公共方法有:toString
Student类的公共方法返回值类型有:class java.lang.String
Student类的公共方法的修饰符有:[Ljava.lang.Class;@232204a1
Student类的公共方法的形参有:public
Student及其父类的公共方法:public native int java.lang.Object.hashCode()
Student类的公共方法有:hashCode
Student类的公共方法返回值类型有:int
Student类的公共方法的修饰符有:[Ljava.lang.Class;@4aa298b7
Student类的公共方法的形参有:public native
Student及其父类的公共方法:public final native java.lang.Class java.lang.Object.getClass()
Student类的公共方法有:getClass
Student类的公共方法返回值类型有:class java.lang.Class
Student类的公共方法的修饰符有:[Ljava.lang.Class;@7d4991ad
Student类的公共方法的形参有:public final native
Student及其父类的公共方法:public final native void java.lang.Object.notify()
Student类的公共方法有:notify
Student类的公共方法返回值类型有:void
Student类的公共方法的修饰符有:[Ljava.lang.Class;@28d93b30
Student类的公共方法的形参有:public final native
Student及其父类的公共方法:public final native void java.lang.Object.notifyAll()
Student类的公共方法有:notifyAll
Student类的公共方法返回值类型有:void
Student类的公共方法的修饰符有:[Ljava.lang.Class;@1b6d3586
Student类的公共方法的形参有:public final native

7.3.2 获取该类本身所声明的所有方法

代码如下(示例):

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Test2 {

	public static void main(String[] args) {
		// 获取自定义的Student类的Class对象
		Class<?> clazz = Student.class;
		// 获取自定义的Student本身所声明的所有方法
		Method[] methods = clazz.getDeclaredMethods();
		for(Method m:methods) {
			System.out.println("Student及其父类的本身所声明的所有方法:"+m);
			// 获取Student类的方法的名称
			String name = m.getName();
			// 获取方法返回值类型
			Class<?> returnType = m.getReturnType();
			// 获取Student类的方法的修饰符
			int modifiers = m.getModifiers();
			String modifierString = Modifier.toString(modifiers);
			// 获取方法的形参
			Class<?>[] parameterTypes = m.getParameterTypes();
			// 获取方法抛出的异常
			Class<?>[] exceptionTypes = m.getExceptionTypes();
			for(Class<?> exc:exceptionTypes) {
				System.out.println("Student类所有本身所声明的所有方法的异常有:"+exc);
			}
			System.out.println("Student类的本身所声明的所有方法有:"+name);
			System.out.println("Student类的本身所声明的所有方法返回值类型有:"+returnType);
			System.out.println("Student类的本身所声明的所有方法的修饰符有:"+parameterTypes);
			System.out.println("Student类的本身所声明的所有方法的形参有:"+modifierString);
		}
		
	}
}

代码如下(输出):

Student及其父类的本身所声明的所有方法:public int com.etime2.Student.getAge()
Student类的本身所声明的所有方法有:getAge
Student类的本身所声明的所有方法返回值类型有:int
Student类的本身所声明的所有方法的修饰符有:[Ljava.lang.Class;@5c647e05
Student类的本身所声明的所有方法的形参有:public
Student及其父类的本身所声明的所有方法:private void com.etime2.Student.setAge(int)
Student类的本身所声明的所有方法有:setAge
Student类的本身所声明的所有方法返回值类型有:void
Student类的本身所声明的所有方法的修饰符有:[Ljava.lang.Class;@33909752
Student类的本身所声明的所有方法的形参有:private
Student及其父类的本身所声明的所有方法:private java.lang.String com.etime2.Student.printInfo(java.lang.String)
Student类的本身所声明的所有方法有:printInfo
Student类的本身所声明的所有方法返回值类型有:class java.lang.String
Student类的本身所声明的所有方法的修饰符有:[Ljava.lang.Class;@55f96302
Student类的本身所声明的所有方法的形参有:private
Student及其父类的本身所声明的所有方法:public static void com.etime2.Student.printDate()
Student类的本身所声明的所有方法有:printDate
Student类的本身所声明的所有方法返回值类型有:void
Student类的本身所声明的所有方法的修饰符有:[Ljava.lang.Class;@3d4eac69
Student类的本身所声明的所有方法的形参有:public static

7.3.3 获取指定的公共方法

代码如下(示例):

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Test3 {

	public static void main(String[] args) throws Exception {
		// 获取自定义的Student类的Class对象
		Class<?> clazz = Student.class;
		// 获取自定义的Student类的getAge方法
		Method method = clazz.getMethod("getAge");
		// 获取Student类的getAge方法的名称
		String name = method.getName();
		// 获取getAge方法返回值类型
		Class<?> returnType = method.getReturnType();
		// 获取Student类的getAge方法的修饰符
		int modifiers = method.getModifiers();
		String modifierString = Modifier.toString(modifiers);
		// 获取getAge方法的形参
		Class<?>[] parameterTypes = method.getParameterTypes();
		// 获取getAge方法抛出的异常
		Class<?>[] exceptionTypes = method.getExceptionTypes();
		for (Class<?> exc : exceptionTypes) {
			System.out.println("Student类getAge方法的异常有:" + exc);
		}
		System.out.println("Student类getAge方法的名字为:" + name);
		System.out.println("Student类getAge方法返回值类型有:" + returnType);
		System.out.println("Student类getAge方法的修饰符有:" + parameterTypes);
		System.out.println("Student类getAge方法的形参有:" + modifierString);
	}
}

代码如下(输出):

Student类getAge方法的名字为:getAge
Student类getAge方法返回值类型有:int
Student类getAge方法的修饰符有:[Ljava.lang.Class;@5c647e05
Student类getAge方法的形参有:public

7.3.4 获取指定的声明方法

代码如下(示例):

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Test4 {

	public static void main(String[] args) throws Exception {
		// 获取自定义的Student类的Class对象
		Class<?> clazz = Student.class;
		// 获取自定义的Student类的setAge方法
		Method declaredMethod = clazz.getDeclaredMethod("setAge", int.class);
		// 获取Student类的setAge方法的名称
		String name = declaredMethod.getName();
		// 获取setAge方法返回值类型
		Class<?> returnType = declaredMethod.getReturnType();
		// 获取Student类的setAge方法的修饰符
		int modifiers = declaredMethod.getModifiers();
		String modifierString = Modifier.toString(modifiers);
		// 获取setAge方法的形参
		Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
		// 获取setAge方法抛出的异常
		Class<?>[] exceptionTypes = declaredMethod.getExceptionTypes();
		for (Class<?> exc : exceptionTypes) {
			System.out.println("Student类setAge方法的异常有:" + exc);
		}
		System.out.println("Student类setAge方法的名字为:" + name);
		System.out.println("Student类setAge方法返回值类型有:" + returnType);
		System.out.println("Student类setAge方法的修饰符有:" + parameterTypes);
		System.out.println("Student类setAge方法的形参有:" + modifierString);
	}
}

代码如下(输出):

Student类setAge方法的名字为:setAge
Student类setAge方法返回值类型有:void
Student类setAge方法的修饰符有:[Ljava.lang.Class;@5c647e05
Student类setAge方法的形参有:private

8. 运行时创建类的对象

8.1测试类(自己故意写的,为了方便测试)

public class Student {
	public String name;
	private int age;
	public Student() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
}

8.2 API

通过class.newInstance()调用无参构造函数创建对象

Object java.lang.Class.newInstance() throws InstantiationException, IllegalAccessException

通过constructor.newInstance()调用有参构造函数创建对象

T java.lang.reflect.Constructor.newInstance(Object... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException

8.3 运行时创建类的对象代码演示

8.3.1 通过class.newInstance()调用无参构造函数创建对象

代码如下(示例):

public class Test1 {

	public static void main(String[] args) throws Exception {
		// 获取自定义的Student类的Class对象
		Class<?> clazz = Student.class;
		//通过class.newInstance()调用无参构造函数创建对象
		Object newInstance = clazz.newInstance();
		System.out.println("创建好的对象所在地址为:"+newInstance);
	}
}

代码如下(输出):

创建好的对象所在地址为:com.et.Student@70dea4e

8.3.2 //通过constructor.newInstance()调用有参构造函数创建对象

代码如下(示例):

public class Test2 {

	public static void main(String[] args) throws Exception {
		// 获取自定义的Student类的Class对象
		Class<?> clazz = Student.class;
		// 通过constructor.newInstance()调用有参构造函数创建对象
		Object newInstance = clazz.getConstructor(String.class,int.class).newInstance("小明",18);
		System.out.println("创建好的对象所在地址为:"+newInstance);
	}
}

代码如下(输出):

创建好的对象所在地址为:com.et.Student@70dea4e

9. 运行时操作对象的成员变量

9.1测试类(自己故意写的,为了方便测试)

import java.io.Serializable;

public class Student implements Serializable {
	private static final long serialVersionUID = 1L;
	public String name;
	public String city;
	private int age;
	public Student() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Student(String name, String city, int age) {
		super();
		this.name = name;
		this.city = city;
		this.age = age;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", city=" + city + ", age=" + age + "]";
	}
	
}

9.2 API

获取类的字段

Field java.lang.Class.getDeclaredField(String name) throws NoSuchFieldException, SecurityException

获取对象的成员变量的值

Object java.lang.reflect.Field.get(Object obj) throws IllegalArgumentException, IllegalAccessException

设置对象的成员变量的值

void java.lang.reflect.Field.set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException

9.3 运行时操作对象的成员变量代码演示

9.3.1 访问非静态成员变量

代码如下(示例):

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class TestField {

	public static void main(String[] args) throws Exception {
		Class<?> clazz = Student.class;
		Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(String.class,String.class,int.class);
		Object student = declaredConstructor.newInstance("张三","上海",18);
		Field field = clazz.getDeclaredField("name");
		field.setAccessible(true);
		Object value = field.get(student);
		System.out.println(value);
		field.set(student, "llili");
		System.out.println(student);
		
	}
}

代码如下(输出):

张三
Student [name=llili, city=上海, age=18]

9.3.2 访问静态成员变量

代码如下(示例):

import java.lang.reflect.Field;

public class Test2 {

	public static void main(String[] args) throws Exception {
		Class<?> clazz = Student.class;
        Field field = clazz.getDeclaredField("serialVersionUID");
        field.setAccessible(true);
        Object value = field.get(null);
        System.out.println(value);
	}
}

代码如下(输出):

1

10. 运行时操作对象的成员方法

10.1测试类(自己故意写的,为了方便测试)

import java.io.Serializable;

public class Student implements Serializable {
	private static final long serialVersionUID = 1L;
	public String name;
	private int age;
	public Student() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
}

10.2 API

访问成员方法

Object java.lang.reflect.Method.invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException

10.3 运行时操作对象的成员方法代码演示

10.3.1 访问非静态成员方法

代码如下(示例):

  import java.lang.reflect.Method;

public class Test1 {

	public static void main(String[] args) throws Exception {
		Class<?> clazz = Student.class;
		Object student = clazz.newInstance();
		Method declaredMethod = clazz.getDeclaredMethod("setName", String.class);
		declaredMethod.invoke(student, "小红");
		Method getMethod = clazz.getDeclaredMethod("getName");
		Object value = getMethod.invoke(student);
		System.out.println(value);
	}
}

代码如下(输出):

小红

10.3.2 访问静态成员方法

代码如下(示例):

import java.lang.reflect.Method;

public class Test2 {

	public static void main(String[] args) throws Exception {
		Class<?> clazz = Student.class;
        Method staticMethod = clazz.getDeclaredMethod("printDate");
        Object value = staticMethod.invoke(null);
        System.out.println(value);
	}

代码如下(输出):

Tue Mar 16 20:24:11 CST 2021
null

总结

反射建立在运行时,这一点一定一定要记住,这是刚需

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/5064.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!