跟我学Java反射——二步曲

上一篇文章我们已经将反射的基本知识和class类以及类的加载器进行了介绍,在上一篇我们还学习了四种得到Class类对象的方式,但是有了class对象我们能做些什么呢,学习完这篇文章,就可以得到答案了.

获取类的完整结构

这篇文章我们主要通过demo来学习,我先将demo需要用到的代码进行简单介绍.

一个接口MyInterface代码:

package com.tgb.reflect.common;

import java.io.Serializable;

public interface MyInterface<T> extends Serializable {

}

一个父类Creature,代码是:

package com.tgb.reflect.common;

public class Creature<T,N> {

	public double weight;
	public Creature(){}
	public void breath() {
		System.out.println("我是父类Creature的breath()方法");
	}

}

一个注解类MyAnnotation,代码是:

package com.tgb.reflect.common;

import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
	public String value();
}

一个Person类,代码是:

package com.tgb.reflect.common;

/**
 * Person类继承泛型Creature父类,实现两个接口,本类含有不同权限修饰符修饰的变量
 * 含有不同权限修饰符修饰、不同参数的构造函数;含有不同权限修饰符修饰、不同参数的方法;
 * @author kang
 *
 */
@MyAnnotation(value = "tgb")
public class Person extends Creature<String,Object> implements Comparable<Integer>,MyInterface<String> {

	//不同权限修饰符修饰的变量
	private int age;
	public String name;
	int id;

	//不同权限修饰符修饰的拥有不同参数构造函数
	private Person(String name) {
		super();
		this.name = name;
		System.out.println("我是Person类的private修饰的带参数构造函数Person(String name) ");
	}
	public Person() {
		super();
		System.out.println("我是Person类的public修饰的空参构造函数Person()");
	}
	Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
		System.out.println("我Person类的修饰符的带参构造函数Person(String name, int age)");

	}

	@Override
	public String toString() {
		System.out.println("我是Person类的public修饰的空参方法toString()");
		return "Person [name=" + name + ", age=" + age + "]";

	}

	@MyAnnotation(value = "abc123")
	public void show(){
		System.out.println("我是Person类的public修饰的带注解的show()空参方法");
	}

	private void display(String nation){
		System.out.println("我是Person类的public修饰的带注解的display()有参方法,参数是:"+nation);
	}

	public static void info(){
		System.out.println("我是Person类的public修饰的info()空参静态方法");
	}

	class Bird{}

	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;
	}
	@Override
	public int compareTo(Integer o) {
		return 0;
	}
}

获取运行类构造函数

我们可以用得到的Class对象,通过反射来获取该Class对象的所有构造函数,

获取运行类权限修饰符为public的构造函数

//获取运行类权限修饰符为public的构造函数
@Test
public void test2(){
	String className = "com.tgb.reflect.common.Person";
	Class class1 = Class.forName(className);
<span style="white-space:pre">	</span>Constructor[] conClasses=clazz.getConstructors();
	for (int i = 0; i < conClasses.length; i++) {
		System.out.println(conClasses[i]);
	}
}

运行结果为:

public com.tgb.reflect.common.Person()

获取运行类所有的构造函数

//获取运行类所有的构造函数
@Test
public void test2() throws ClassNotFoundException{
	String className = "com.tgb.reflect.common.Person";
	Class clazz = Class.forName(className);

	Constructor[] conClasses=clazz.getDeclaredConstructors();
	for (int i = 0; i < conClasses.length; i++) {
		System.out.println(conClasses[i]);
	}
}

运行结果:

com.tgb.reflect.common.Person(java.lang.String,int)

publiccom.tgb.reflect.common.Person()

privatecom.tgb.reflect.common.Person(java.lang.String)

由此我们得出结论,getConstructors()可以获得运行类的public的构造函数,getDeclaredConstructors()可以获得运行类的所有构造函数。

获取运行类对象实例

我们可以用得到的Class对象,来创建类的对象实例,在创建对象实例时,要就用到了我们刚才上面讲到的构造函数,不同的构造函数,创建对象实例的方法也是不一样的.

空参构造器

//利用运行类的空参构造函数,来创建运行类对象的实例
@Test
public void test1() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException{
	String className = "com.tgb.reflect.common.Person";
	Class class1 = Class.forName(className);

	//获取运行类的空参构造函数
	Constructor constructor = class1.getConstructor();
	//创建对应的运行类对象时,使用newInstance,实际上就是调用了运行时类的空参的构造器;
	Person person = (Person)constructor.newInstance();
	System.out.println(person);
}

运行结果:

我是Person类的public修饰的空参构造函数Person()

我是Person类的public修饰的空参方法toString()

Person [name=null,age=0]

非空参构造器

	// 利用运行类的非空参构造函数,创建运行类的实例对象
	@Test
	public void test4() throws ClassNotFoundException, NoSuchMethodException,
			SecurityException, InstantiationException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException {
		String className = "com.tgb.reflect.common.Person";
		Class class1 = Class.forName(className);

		// 获取运行类的带参数的构造函数
		Constructor constructor = class1.getDeclaredConstructor(String.class,
				int.class);
		constructor.setAccessible(true);
		// 利用构造器创建运行类的实例对象
		Person p = (Person) constructor.newInstance("luowei", 20);
		System.out.println(p);
	}

运行结果:

我Person类的修饰符的带参构造函数Person(Stringname, int age)

我是Person类的public修饰的空参方法toString()

Person [name=luowei,age=20]

通过上面两种方法,我们可以学习到的利用空参和非空参构造器来创建运行类的实例对象

有了Class类对象除了可以通过构造函数获取运行类实例,还可以获取运行类的其它一些内容.

获取运行类父类

1.获取运行类的父类

// 1.获取运行类的父类
@Test
public void test1() {
	Class class1 = Person.class;
	Class parentClass = class1.getSuperclass();
	System.out.println(parentClass);

}

运行结果:

classcom.tgb.reflect.common.Creature

2.获取运行类的带着泛型的父类

由于我们的父类是带着泛型的,通过上面这种获取到的父类并没有带泛型,所有我们可以通过以下方法来获取运行类的带着泛型的父类.

// 2.获取运行类的带着泛型的父类
@Test
public void test2() {
	// 得到运行类本身
	Class class1 = Person.class;

	// 得到运行类的带泛型的父类
	Type type = class1.getGenericSuperclass();
	System.out.println(type);
}

运行结果:

com.tgb.reflect.common.Creature<java.lang.String,java.lang.Object>

3.获取运行类的父类的泛型

我们已经得到带着泛型的父类了,现在我们要得到父类的泛型,我们可以用接下来的方法.

// 3.获取运行类的父类的泛型
@Test
public void test3() throws ClassNotFoundException{
	//通过类加载器得到运行类本身
	String className= "com.tgb.reflect.common.Person";
	ClassLoader classLoader =this.getClass().getClassLoader();
	Class class1=classLoader.loadClass(className);

	//得到运行类的带泛型的父类
	Type type = class1.getGenericSuperclass();
	ParameterizedType param = (ParameterizedType) type;
	Type[] types= param.getActualTypeArguments();
	for (int i = 0; i < types.length; i++) {
		System.out.println(((Class)types[i]).getName());
	}
}

运行结果:

java.lang.String

java.lang.Object

获取运行类实现的接口

1.获取运行类实现的所有接口

	//1.获取运行类实现的接口
	@Test
	public void test1() throws ClassNotFoundException{
		//通过类加载器得到运行类本身
		String className= "com.tgb.reflect.common.Person";
		ClassLoader classLoader =this.getClass().getClassLoader();
		Class class1=classLoader.loadClass(className);

		//获取运行类实现的接口
		Class[] interfaces=class1.getInterfaces();

		for (int i = 0; i < interfaces.length; i++) {
			System.out.println(interfaces[i]);
		}
	}

运行结果:

interfacejava.lang.Comparable

interfacecom.tgb.reflect.common.MyInterface

2.获取运行类的带着泛型的接口

//2.获取运行类实现的带泛型的接口
@Test
public void test2() throws ClassNotFoundException{
	//通过类加载器得到运行类本身
	String className= "com.tgb.reflect.common.Person";
	ClassLoader classLoader =this.getClass().getClassLoader();
	Class class1=classLoader.loadClass(className);

	//获取运行类实现的接口
	Type[] types=class1.getGenericInterfaces();
	for (int i = 0; i < types.length; i++) {
		System.out.println(types[i]);
	}
}

运行结果:

java.lang.Comparable<java.lang.Integer>

com.tgb.reflect.common.MyInterface<java.lang.String>

3.获取运行类的接口的泛型

	//3.获取运行类实现的带泛型的接口
	@Test
	public void test3() throws ClassNotFoundException{
		//通过类加载器得到运行类本身
		String className= "com.tgb.reflect.common.Person";
		ClassLoader classLoader =this.getClass().getClassLoader();
		Class class1=classLoader.loadClass(className);

		//获取运行类实现的接口
		Type[] types=class1.getGenericInterfaces();

		for (int i = 0; i < types.length; i++) {
			//获取每一个接口的泛型参数类型
			ParameterizedType params = (ParameterizedType) types[i];
			Type[] para= params.getActualTypeArguments();
			for (int j = 0; j < para.length; j++) {
				System.out.println(((Class)para[j]).getName());
			}
		}

运行结果:

java.lang.Integer

java.lang.String

通过上面的介绍我们可以获取到运行类接口、泛型接口和泛型的具体类型。

获取运行类的所在的包

//1.获取运行类的所在的包
@Test
public void test6(){
	//通过运行类本身来得到运行类
	Class class1 = Person.class;

	Package packageClass = class1.getPackage();
	System.out.println(packageClass.getName());
}

运行结果:

com.tgb.reflect.common

获取运行类的注解

	//获取运行类的注解
	@Test
	public void test7(){
		//通过运行类本身来得到运行类
		Class class1 = Person.class;
		//得到运行类的注解
		Annotation[] annotations=class1.getAnnotations();
		for (int i = 0; i < annotations.length; i++) {
			System.out.println(annotations[i]);
		}
	}

运行结果:

@com.tgb.reflect.common.MyAnnotation(value=tgb)

后记

这篇文章我们通过具体代码学习了,如何在得到运行类的Class对象后通过反射得到运行类的空参和有参的构造函数,并通过这些构造函数生成运行类的实例对象,同时还可以得到运行类的父类和接口,以及包括泛型父类、泛型接口、父类或者接口具体的泛型。下篇文章我们继续反射的学习。

时间: 2024-08-27 03:23:30

跟我学Java反射——二步曲的相关文章

跟我学Java反射——一步曲

反射是什么 Reflection(反射)就是Java程序在运行时可以动态得到程序内部所有类的内部信息,并能动态调用任意对象的内部属性和方法. 为什么需要反射 我们为什么要用反射,这主要是反射的动态性决定的,由于反射可以实现动态创建对象,这就很大程度发挥了java的灵活性,降低了程序调用的耦合性,使系统可以更加的灵活,可以更好的应对变化. 反射应用 运行反射我们可以做到: 在运行时判断任意一个对象所属的类 在运行时构造任意一个类的对象 在运行时判断任意一个类所具有的成员变量和方法 在运行时调用任意

跟我学Java反射——三步曲

上一篇文章我们通过反射得到运行类的构造函数.对象实例.父类.实现的接口.所在包.以及注解,这篇文章我们将学习通过反射得到运行类的相关属性信息以及相关的方法信息. 获取类的完整结构 运行类的Field 通过运行类来获取它的相关属性,这一点在开发中用途还是很广泛的,下面我们就来看下跟Field相关的知识. 1.获取到运行类中及其父类中声明为public的属性 //获取到运行类中及其父类中声明为public的属性 @Test public void Test1(){ Class clazz = Per

菜鸟学Java(二十)——你知道long和Long有什么区别吗?

Java中数据类型分两种: 1.基本类型:long,int,byte,float,double2.对象类型:Long,Integer,Byte,Float,Double其它一切java提供的,或者你自己创建的类. 其中Long叫 long的包装类.Integer.Byte和Float也类似,一般包装类的名字首写是数值名的大写开头. 什么是包装类? 在java中有时候的运算必须是两个类对象之间进行的,不充许对象与数字之间进行运算.所以需要有一个对象,这个对象把数字进行了一下包装,这样这个对象就可以

菜鸟学Java(二十一)——如何更好的进行单元测试——JUnit

测试在软件声明周期中的重要性,不用我多说想必大家也都非常清楚.软件测试有很多分类,从测试的方法上可分为:黑盒测试.白盒测试.静态测试.动态测试等:从软件开发的过程分为:单元测试.集成测试.确认测试.验收.回归等. 在众多的分类中,与开发人员关系最紧密的莫过于单元测试了.像其他种类的测试基本上都是由专门的测试人员来完成,只有单元测试是完全由开发人员来完成的.那么今天我们就来说说什么是单元测试,为什么要进行单元测试,以及如更好的何进行单元测试. 什么是单元测试? 单元测试(unit testing)

重学JAVA基础(二):Java反射

看一下百度的解释: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息    以及动态调用对象的方法的功能称为java语言的反射机制. 先看一下一个例子: 这是最简单的反射使用方法,通过反射来调用类的方法. 下面通过一个需求来做反射实验:有3种人类(黄,白,黑),分别继承于Human类,都有人类的共同操作Behaviour /** * 行为,区别于动物 * @author tomsnail *

工作流学习——Activiti整体认识二步曲 (zhuan)

http://blog.csdn.net/zwk626542417/article/details/46594505 *********************************************** 一.前言 在上一篇文章中我们将工作流的相关概念.activiti的前世今生.activiti与jbpm的比较进行学习,这篇文章我们正式进行activiti的学习,activiti的整个学习我们主要通过例子的形式来理解.今天我们主要是准备下activiti的环境,在数据库中创建activ

跟我学Java反射——四步曲

前面的三篇文章我们将反射的基础知识和通过反射来得到运行类的结构,比如.属性.方法.父类.接口.注解等一些内容,并对如何通过反射来调用运行类的指定属性和方法,这篇文章我们学习一个运行反射的典型,动态代理与AOP的结合. AOP动态代理 先来介绍一种情况,代码段1.2.3都含有相同的代码段,以前的方法通过复杂粘贴重复的代码段来完成,如图: 上面描述的这种情况,必然是可以进行改进的,我们将重复的代码抽离出来,让代码段1.2.3通过方法调用的形式来调用抽离出来的那段重复的代码段,这样相对于上面的图来说,

一起学Java(二十四)-----hashcode()和equals()

不积跬步,无以至千里:不积小流,无以成江海. Java语言基础 Java的hashcode()和equals()方法 equals() 比较两个对象是否相等,它与 == 的比较有本质的不同, 在Java 体系中,系统把判断对象是否相等的权力交给程序员.具体的措施是把 equals() 方法写到 Object 类中,并让所有类继承 Object 类. 这样程序员就能在自定义的类中重写 equals() 方法, 从而实现自己的比较逻辑. hashCode() hashCode() 的意思是哈希值,哈

一起学Java(二十六)----- 对象之间赋值

不积跬步,无以至千里:不积小流,无以成江海. Java语言基础 Java对象之间赋值 赋值是用等号运算符“ = ”进行的,在对对象进行“赋值”时,实际就是将句柄从一个地方复制到另一个地方.这意味着假若为对象使用“A = B”,那么A和B最终都会指向最初只有B才指向的那个对象.也就是说这个时候他们两个引用了同一块内存地址. class Number{ int i; } public class Test { public static void main(String[] args) { Numb