文档章节

Java 反射

tsmyk0715
 tsmyk0715
发布于 2017/06/05 12:01
字数 2431
阅读 25
收藏 0

Java 反射

1. 获取 Class 的三种方法:

public class Clazz01 {

	public Class<?> method01(){
		Class<?> clazz = Clazz01.class;
		return clazz;
	}
	
	//常用
	public Class<?> method02(){
		try {
			Class<?> clazz = Class.forName("reflect.Clazz01");
			return clazz;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public Class<?> method03(){
		Clazz01 clazz01 = new Clazz01();
		Class<?> clazz = clazz01.getClass();
		return clazz;
	}
	
	public static void main(String[] args) {
		Clazz01 c = new Clazz01();
		Class<?> clazz1 = c.method01();
		Class<?> clazz2 = c.method02();
		Class<?> clazz3 = c.method03();
		System.out.println(clazz1);//class reflect.Clazz01
		System.out.println(clazz2);//class reflect.Clazz01
		System.out.println(clazz3);//class reflect.Clazz01
		System.out.println(clazz1.equals(clazz2));//true
		
		System.out.println(clazz1.getName());//reflect.Clazz01
		System.out.println(clazz1.getSimpleName());//Clazz01
	}
}

2. Class 实例化对象

参考的类:

class Person {

	private String name;

	private int age;

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

	public Person(String name) {
		this.name = name;
	}

	public Person() {
	}

	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](https://my.oschina.net/u/1162528)
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
}
	
class Person2 {

	private String name;

	private int age;

	private Person2(String name, int age) {
		this.name = name;
		this.age = age;
	}

	protected Person2(String name) {
		this.name = name;
	}

	public Person2() {
	}

	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](https://my.oschina.net/u/1162528)
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
}

首先获取 **Class**对象:

Class<?> clazz = Class.forName("reflect.Person");

这种方式通过无参构造实例化对象,此时类中必须有一个无参的构造器,否则报错。

通过 **newInstance()**来实例化对象,之后调用相应的方法设置属性值:

Person person = (Person) clazz.newInstance();
person.setName("zhangsan");
person.setAge(20);
System.out.println(person);
// Person [name=zhangsan, age=20]

<br> #####获取构造函数的四种方式:

这两种方式只能获取得到 public 修饰的构造函数:

Constructor<?>[] getConstructors():获取所有的构造函数

Constructor<T> getConstructor(Class<?>... parameterTypes):通过对应的参数看获取对应的构造函数

<br> 这两种方式可以获取到所有的构造函数:`public`, `protected`, `private`,`default`, 常用

Constructor<?>[] getDeclaredConstructors()

Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)

<br> #####1. **`getConstructors()`** : 获取所有的 public 修饰的构造函数:

Constructor<?> cons[] = clazz.getConstructors();
for (int i = 0; i < cons.length; i++) {
	System.out.println(cons[i].toString());
}

结果:

public reflect.Person() 
public reflect.Person(java.lang.String) 
public reflect.Person(java.lang.String, int)

newInstance()的重载:

Person p1 = (Person) cons[0].newInstance();
System.out.println(p1);// Person [name=null, age=0]

Person p2 = (Person) cons[1].newInstance("lisi");
System.out.println(p2);// Person [name=lisi, age=0]

Person p3 = (Person) cons[2].newInstance("lisi", 20);
System.out.println(p3);// Person [name=lisi, age=20]

<br>

2. Constructor<T> getConstructor(Class<?>... parameterTypes): 根据参数来获取 public 修饰的构造函数
Constructor<?> con = clazz.getConstructor(String.class);
Person p4 = (Person) con.newInstance("lisi");
System.out.println(p4);//Person [name=lisi, age=0]

<br> ##### 3. `getDeclaredConstructors()` : 获取所有的类型的构造函数: `public`, `protected`, `private`, `default`:

Class<?> clazz2 = Class.forName("reflect.Person2");
Constructor<?>[] cons2 = clazz2.getDeclaredConstructors();
for (int i = 0; i < cons2.length; i++) {
	System.out.println(cons2[i].toString());
}

结果:

public reflect.Person2() 
protected reflect.Person2(java.lang.String)  
private reflect.Person2(java.lang.String,int)

<br> #####4. `Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)` : 根据参数获取 `private `的构造函数

	Constructor<?> c = clazz2.getDeclaredConstructor(String.class,int.class);
	System.out.println(c);
	//private reflect.Person2(java.lang.String,int)
	c.setAccessible(true);//为 true, 则可以访问所有的方法和字段,包括 private
	
	Person2 p = (Person2) c.newInstance("zhangsan", 20);
	System.out.println(p);//Person [name=zhangsan, age=20]

<br> #### 3. 获取类实现的 接口 和 父类

参考的类:

interface World<A, B> {
	void sayWorld();	
	A getA();	
	B getB();
}

interface A {

}

interface B {

}

abstract class China<T> {
	public static final String name = "lisi";
	public static final int age = 20;
	public abstract void sayChina();
	public abstract void hello(String name);
}

class Person3<T> extends China<T> implements World<A, B>, A, B {

	[@Override](https://my.oschina.net/u/1162528)
	public void sayWorld() {
		System.out.println("say world...");
	}

	[@Override](https://my.oschina.net/u/1162528)
	public void sayChina() {
		System.out.println("say china...");
	}

	[@Override](https://my.oschina.net/u/1162528)
	public void hello(String name) {
		System.out.println("hello : " + name);
	}

	@Override
	public A getA() {
		return null;
	}

	@Override
	public B getB() {
		return null;
	}
}

<br> ##### 获取类所实现的===> 接口

getInterfaces() : 返回本类直接实现的所有接口. 不包含泛型参数信息

Class<?> clazz = Class.forName("reflect.Person3");

.

Class<?>[] interfs = clazz.getInterfaces();
	for (Class<?> interf : interfs) {
		// 获取接口的名字
		System.out.println(interf.getName());// reflect.World
		// 获取接口下的所有方法,包括 prorected, private
		Method[] methods = interf.getDeclaredMethods();
		for (Method method : methods) {
			// 获取方法名
			System.out.println(method.getName());// sayWorld
		}
}

结果:

reflect.World 
sayWorld 
getA 
getB
 
reflect.A 
reflect.B

<br> `getGenericInterfaces()`: 以**`Type`**的形式返回本类直接实现的接口. 这样就包含了泛型参数信息

Type[] types = clazz.getGenericInterfaces();
for (Type type : types) {
	System.out.println(type);
}

结果:

reflect.World<reflect.A, reflect.B> 
interface reflect.A 
interface reflect.B

<br> ##### 获取本类的===>父类

getSuperclass() : 不包含泛型信息

 Class<?> supClazzes = clazz.getSuperclass();
String className = supClazzes.getName();
System.out.println(className);//reflect.China

getGenericSuperclass() : 包含泛型信息

Type type =clazz.getGenericSuperclass();
System.out.println(type);//reflect.China<T>

<br> ####4. 获取所有的方法

参考的类:

abstract class China2 {
	public static final String name = "lisi";		
	public static final int age = 20;	
	protected abstract void sayChina();	
	abstract void hello(String name);
}

class Person4 extends China2{

	private String sex;

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	@Override
	protected void sayChina() {
		System.out.println("say china...");
	}

	@Override
	void hello(String name) {
		System.out.println("hello : " + name);
	}

	private Person4(String sex) {
		super();
		this.sex = sex;
	}

	public Person4() {
		super();
	}
	
}

首先获取 Class 对象:

Class<?> clazz = Class.forName("reflect.Person4");

通过反射来获取一个类的方法:

  1. getMethods(): 获取本类中的所有 public的方法,包括所实现的接口和父类中的方法
  2. getMethod(String name, Class<?>... parameterTypes) : 根据方法名和参数来获取对应的public方法, 可以获取实现的 接口 和 父类 中的方法
  3. getDeclaredMethods() : 获取本类中所有的方法,包括 protected, privatedefault, 不包含接口和父类
  4. getDeclaredMethods(String name, Class<?>... parameterTypes) : 根据方法名和参数来获取对应的方法,包括protected, private, default,但是不包含继承来的方法

getMethods(): 只能获取 public 修饰的方法,可以获取实现的 接口 和 父类 中的方法

	Method[] methods = clazz.getMethods();
	for (Method method : methods) {
		
		// 获取访问修饰符
		int modifier = method.getModifiers();
		System.out.print(Modifier.toString(modifier) + " ");
		
		// 获取返回值类型
		Class<?> returnType = method.getReturnType();
		String returnTypeName = returnType.getName();
		System.out.print(returnTypeName + " ");
		
		// 获取方法名
		String methodName = method.getName();
		System.out.print(methodName);
			
		System.out.print("(");
		
		// 获取参数类型
		Class<?>[] paramTypes = method.getParameterTypes();
		// 获取参数
		Parameter[] params = method.getParameters();
		for(int i = 0; i < paramTypes.length; i++){
			System.out.print(params[i]);// 参数已经包含类型信息了:java.lang.String arg0
			if(i < paramTypes.length - 1){
				System.out.print(", ");
			}
		}
		
		// 获取异常类型
		Class<?>[] exceptionTypes = method.getExceptionTypes();
		if(exceptionTypes.length > 0){
			System.out.print(") throws ");
			for (int i = 0; i < exceptionTypes.length; i++) {
				System.out.println(exceptionTypes[i].getName());
				if(i < exceptionTypes.length - 1){
					System.out.print(", ");
				}
			}
		}else{
			System.out.println(")");
		}
		System.out.println();
	}

结果:

public java.lang.String getSex()	 
public void setSex(java.lang.String arg0)	
public final void wait() throws java.lang.InterruptedException	
public final void wait(long arg0, int arg1) throws java.lang.InterruptedException  	
public final native void wait(long arg0) throws java.lang.InterruptedException	

public boolean equals(java.lang.Object arg0)

<br> **`getMethod(String name, Class<?>... parameterTypes)`**根据方法名称可参数来获取对应的 public 方法,可以获取实现的 接口 和 父类 中的方法

Method me = clazz.getMethod("getSex");
System.out.println(me);
//public java.lang.String reflect.Person4.getSex()

<br> **`getDeclaredMethods()`** 获取本类中所有的方法, 包括 protected, private 的方法

Method[] decMethods = clazz.getDeclaredMethods();
for(Method m : decMethods){
	System.out.println(m.getName());
}

结果:

getSex
hello
setSex
sayChina

<br> **`getDeclaredMethods(String name, Class<?>... parameterTypes)` **根据方法名和参数类型获取所有方法,包括 protected, private, defalut

Method m = clazz.getDeclaredMethod("hello", String.class);
System.out.println(m);
//void reflect.Person4.hello(java.lang.String)

<br> ####5. 获取属性

参考的类:

class FPerson{
	private String name;
	int age;
	protected float weight;
	public boolean isMen;
}

class Person_ extends FPerson{
	private byte photo;
	char pchar;
	protected short hight;
	public double sing;
}

<br> 首先获取**`Class`**对象:

Class<?> clazz = Class.forName("reflect.Person_");

获取属性的四个方法:

  1. getFields(): 获取本类中所有的 public 属性,包括父类中的属性
  2. getField(String name): 根据属性名类获取 Field
  3. getDeclaredFields(): 获取本类中所有的属性,包括 protected, private,default, 不能获取父类的属性
  4. getDeclaredField(String name): 根据参数来获取本类的属性,包括 protected, private,default, 不能获取父类的属性, 不包含父类

**getFields()**获取本类中所有的 public 属性,包括父类中的属性

Field[] fields = clazz.getFields();
for(Field field : fields){
	// 获取修饰符
	int mod = field.getModifiers();
	System.out.print(Modifier.toString(mod) + " ");
	
	// 获取属性的类型
	Class<?> type = field.getType();
	System.out.print(type + " ");
	
	String name = field.getName();
	System.out.println(name);
}

结果:

public double sing
public boolean isMen

getField(String name) : 根据属性名类获取 Field, 若在本类中找不到对应的属性,或者有这个属性,但是修饰符不是 public,(也包括在父类中查找), 则会抛出异常:java.lang.NoSuchFieldException

Field f = clazz.getField("isMen");
System.out.println(f);
//public boolean reflect.FPerson.isMen

**getDeclaredFields()**获取本类中所有的属性,包括 protected, private,default, 不能获取父类的属性

Field[] decFields = clazz.getDeclaredFields();
for(Field field : decFields){
	// 获取修饰符
	int mod = field.getModifiers();
	System.out.print(Modifier.toString(mod) + " ");
	
	// 获取属性的类型
	Class<?> type = field.getType();
	System.out.print(type + " ");
	
	String name = field.getName();
	System.out.println(name);
}

结果:

private byte photo
 char pchar
protected short hight
public double sing

getDeclaredField(String name) : 根据参数来获取本类的属性,包括 protected, private,default, 不能获取父类的属性, 不包含父类

<br> #### 6. Class, Field, Method 的一些方法:

参考的类:

class Person6{

	private String name;
	private int age;
	private boolean isMen;
	
	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;
	}
	public boolean isMen() {
		return isMen;
	}
	public void setMen(boolean isMen) {
		this.isMen = isMen;
	}
	public Person6(String name, int age, boolean isMen) {
		super();
		this.name = name;
		this.age = age;
		this.isMen = isMen;
	}
	public Person6() {
		super();
	}
	
	public String teseMethod(String name, int age, boolean men) throws Exception{
		return "test Method'method";
	}
}

<br> 首先获取 `Class`对象:

Class<?> clazz = Class.forName("reflect.Person6");

#####Class的方法:

toGenericString(): 返回CLass, Constructor,Method,Field的详细信息

返回 Class 的详细信息:

String str = clazz.toGenericString();
System.out.println(str);//class reflect.Person6

返回构造方法的详细信息

Constructor<?> cons = clazz.getDeclaredConstructor(String.class, int.class, boolean.class);
System.out.println(cons.toGenericString());
// public reflect.Person6(java.lang.String,int,boolean)

getPackage()获取包

Package pack = clazz.getPackage();
System.out.println(pack);// package reflect
System.out.println(pack.getName());// reflect

getCanonicalName(): 返回 Java 中所定义的底层类的规范化名称。

String canonicalName = clazz.getCanonicalName();
System.out.println(canonicalName);//reflect.Person6

getComponentType: 返回表示数组组件类型的 Class

String[] strArr = {"a", "b", "c"};
Class<?> componentType = strArr.getClass().getComponentType();
System.out.println(componentType.getName());// java.lang.String

<br> #####`Field` 的方法:

Field field = clazz.getDeclaredField("name");

setAccessible(): 设置可以访问私有的属性

	field.setAccessible(true);

getGenericType() : 返回Field 对象所表示字段的类型

	Type type = field.getGenericType();
	System.out.println(type.getTypeName());//java.lang.String

getModifiers():以整数形式返回由该字段的修饰符。

int mod = field.getModifiers();
// Modifier 表示类,接口,属性,方法的修饰符的类
String modStr = Modifier.toString(mod);
System.out.println(mod + "==>" + modStr);// 2==>private

<br> ####7. Java 的动态代理

interface Subject{
	String work(String param);
}

class RealSubject implements Subject{
	@Override
	public String work(String param) {
		return param;
	}
}

class MyHandler implements InvocationHandler{

	private Object obj;
	
	public Object bind(Object obj){
		this.obj = obj;
		Object returnObj = Proxy.newProxyInstance(obj.getClass().getClassLoader(),
				obj.getClass().getInterfaces(), this);
		return returnObj;
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object tmp = method.invoke(obj, args);
		return tmp;
	}
}

测试:

public static void main(String[] args) {
	MyHandler handler = new MyHandler();
	Subject subject = (Subject) handler.bind(new RealSubject());
	String str = subject.work("Java 的动态代理");
	System.out.println(str);
}

结果: Java 的动态代理

8. 使用反射实现工厂模式

// 以后再添加 Animal 的子类,工厂类也不用修改
class AnimalFactory{
	public static Animal getInstance(String className){
		Animal animal = null;
		try {
			animal = (Animal) Class.forName(className).newInstance();
			return animal;
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}
}

interface Animal{
	void run();
}
class Dog implements Animal{
	@Override
	public void run() {
		System.out.println("dog is running");
	}
}
class Cat implements Animal{
	@Override
	public void run() {
		System.out.println("cat is running");
	}
}

测试:

public static void main(String[] args) {
	Animal dog = AnimalFactory.getInstance("reflect.Dog");
	dog.run();// dog is running
	
	Animal cat = AnimalFactory.getInstance("reflect.Cat");
	cat.run();// cat is running
}

看个实际的例子: 利用反射来把父类的属性复制到子类
输入链接说明

© 著作权归作者所有

共有 人打赏支持
上一篇: 观察者模式
下一篇: Spring in Action4-AOP
tsmyk0715
粉丝 34
博文 66
码字总数 147030
作品 0
成都
程序员
私信 提问

暂无文章

降压变换器 Buck

特点 输入输出极性相同。 工作过程 在 MOS 导通时,输入电源通过 L 和 C 滤波后向负载端提供电流;当 MOS 断开后,L 通过二极管续流,保持负载电流连续。输出电压因为占空比的作用,不会超过...

colinux
今天
1
0
Apache日志不记录访问静态文件,访问日志切割,静态元素过期时间设置

Apache配置不记录访问静态文件的日志 网站大多元素为静态文件,如图片、css、js等,这些元素可以不用记录 vhost原始配置 <VirtualHost *:80> ServerAdmin test@163.com DocumentRoo...

野雪球
今天
3
0
聊聊storm的ICommitterTridentSpout

序 本文主要研究一下storm的ICommitterTridentSpout ICommitterTridentSpout storm-core-1.2.2-sources.jar!/org/apache/storm/trident/spout/ICommitterTridentSpout.java public interface......

go4it
今天
4
0
Ubuntu常用操作

查看端口号 netstat -anp |grep 端口号 查看已使用端口情况 netstat -nultp(此处不用加端口号) netstat -anp |grep 82查看82端口的使用情况 查找被占用的端口: netstat -tln netstat -tl...

hc321
昨天
4
0
网站cdn的静态资源突然访问变的缓慢,问题排查流程

1.首先我查看了一下是否自己的网络问题,通过对比其他资源的访问速度和下载速度,确认不是 2.通过ping 和 tracert 判断cdn域名能否正常访问,(最后回想感觉这一步可以省略,因为每次最终能访...

小海bug
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部