1反射机制是什么
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
2反射机制能做什么
反射机制主要提供了以下功能:
在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法;
生成动态代理。
3反射机制的相关API
通过一个对象获得完整的包名和类名
实例化一个类对象(使用构造函数,默认的和带参数的)
返回一个类实现的接口
取得一个类的父类
获得一个类的全部构造函数
可以通过反射调用一个类的方法
调用一个类的set和get方法
通过反射操作属性
通过反射取得并修改数组的信息
通过反射修改数组大小
就看看下面的各式各样的例子,来一步一步的看看反射都能干些什么,都能干嘛,比空谈理论强多了。
例子虽然海了去了,但是耐心看一半,估计你就赢啦。
【案例1】通过一个对象获得完整的包名和类名
package Reflect;
/**
* 通过一个对象获得完整的包名和类名
*/
class Demo {
//other codes...
}
class hello {
public static void main(String[] args) {
Demo demo = new Demo();
System.out.println(demo.getClass().getName());
}
}
【运行结果】:Reflect.Demo
【案例2】实例化Class类对象
package Reflect;
class Demo {
//other codes...
}
class hello {
public static void main(String[] args) {
Class<?> demo1 = null;
Class<?> demo2 = null;
Class<?> demo3 = null;
try {
//一般尽量采用这种形式
demo1 = Class.forName("Reflect.Demo");
} catch (Exception e) {
e.printStackTrace();
}
demo2 = new Demo().getClass();
demo3 = Demo.class;
System.out.println("类名称 " + demo1.getName());
System.out.println("类名称 " + demo2.getName());
System.out.println("类名称 " + demo3.getName());
}
}
【运行结果】:
类名称 Reflect.Demo
类名称 Reflect.Demo
类名称 Reflect.Demo
【案例3】通过Class实例化其他类的对象
通过无参构造实例化对象
package Reflect;
class Person {
private String name;
private int age;
//getters and setters
@Override
public String toString() {
return "[" + this.name + " " + this.age + "]";
}
}
class hello {
public static void main(String[] args) {
Class<?> demo = null;
try {
demo = Class.forName("Reflect.Person");
} catch (Exception e) {
e.printStackTrace();
}
Person per = null;
try {
per = (Person) demo.newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
per.setName("Rollen");
per.setAge(20);
System.out.println(per);
}
}
【运行结果】:
[Rollen 20]
但是注意一下,当我们把Person中的默认的无参构造函数取消的时候,比如自己定义只定义一个有参数的构造函数之后,会出现错误:
比如我定义了一个构造函数:
public Person(String name, int age) {
this.age = age;
this.name = name;
}
然后继续运行上面的程序,会出现:
java.lang.InstantiationException: Reflect.Person
at java.lang.Class.newInstance0(Class.java:340)
at java.lang.Class.newInstance(Class.java:308)
at Reflect.hello.main(hello.java:39)
Exception in thread "main" java.lang.NullPointerException
at Reflect.hello.main(hello.java:47)
所以大家以后再编写使用Class实例化其他类的对象的时候,一定要自己定义无参的构造函数
比如我的这个bug也是因为这个默认构造函数的问题,实例化对象就出错了。
【案例4】通过Class调用其他类中的构造函数 (也可以通过这种方式通过Class创建其他类的对象)
package Reflect;
import java.lang.reflect.Constructor;
class Person {
private String name;
private int age;
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(int age) {
this.age = age;
}
public Person(String name, int age) {
this.age = age;
this.name = name;
}
//getters and setters
@Override
public String toString() {
return "[" + this.name + " " + this.age + "]";
}
}
class hello {
public static void main(String[] args) {
Class<?> demo = null;
try {
demo = Class.forName("Reflect.Person");
} catch (Exception e) {
e.printStackTrace();
}
Person per1 = null;
Person per2 = null;
Person per3 = null;
Person per4 = null;
//取得全部的构造函数
Constructor<?> cons[] = demo.getConstructors();
try {
per1 = (Person) cons[0].newInstance();
per2 = (Person) cons[1].newInstance("Rollen");
per3 = (Person) cons[2].newInstance(20);
per4 = (Person) cons[3].newInstance("Rollen", 20);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(per1);
System.out.println(per2);
System.out.println(per3);
System.out.println(per4);
}
}
【运行结果】:
[null 0]
[Rollen 0]
[null 20]
[Rollen 20]
【案例5】返回一个类实现的接口:
package Reflect;
interface China {
//public static final String name = "Rollen";
//接口中声明前面的类型等修饰符都是多余的
String name = "Rollen";
int age = 20;
void sayChina();
void sayHello(String name, int age);
}
class Person implements China {
private String sex;
public Person() {
}
public Person(String sex) {
this.sex = sex;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public void sayChina() {
System.out.println("hello ,china");
}
@Override
public void sayHello(String name, int age) {
System.out.println(name + " " + age);
}
}
class hello {
public static void main(String[] args) {
Class<?> demo = null;
try {
demo = Class.forName("Reflect.Person");
} catch (Exception e) {
e.printStackTrace();
}
//保存所有的接口
Class<?> intes[] = demo.getInterfaces();
for (int i = 0; i < intes.length; i++) {
System.out.println("实现的接口 " + intes[i].getName());
}
}
}
【运行结果】:
实现的接口 Reflect.China
(注意,以下几个例子,都会用到这个例子的Person类,所以为节省篇幅,此处不再粘贴Person的代码部分,只粘贴主类hello的代码)
【案例6】:取得其他类中的父类
class hello {
public static void main(String[] args) {
Class<?> demo = null;
try {
demo = Class.forName("Reflect.Person");
} catch (Exception e) {
e.printStackTrace();
}
//取得父类
Class<?> temp = demo.getSuperclass();
System.out.println("继承的父类为: " + temp.getName());
}
}
【运行结果】
继承的父类为: java.lang.Object
【案例7】:获得其他类中的全部构造函数
这个例子需要在程序开头添加import java.lang.reflect.*;
然后将主类编写为:
import java.lang.reflect.Constructor;
class hello {
public static void main(String[] args) {
Class<?> demo = null;
try {
demo = Class.forName("Reflect.Person");
} catch (Exception e) {
e.printStackTrace();
}
Constructor<?> cons[] = demo.getConstructors();
for (int i = 0; i < cons.length; i++) {
System.out.println("构造方法: " + cons[i]);
}
}
}
【运行结果】:
构造方法: public Reflect.Person()
构造方法: public Reflect.Person(java.lang.String)
【案例8】接下来让我们取得其他类的全部属性吧,最后我讲这些整理在一起,也就是通过class取得一个类的全部框架
import java.lang.reflect.Modifier;
class hello {
public static void main(String[] args) {
Class<?> demo = null;
try {
demo = Class.forName("Reflect.Person");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("===============本类属性========================");
// 取得本类的全部属性
Field[] field = demo.getDeclaredFields();
for (int i = 0; i < field.length; i++) {
// 权限修饰符
int mo = field[i].getModifiers();
String priv = Modifier.toString(mo);
// 属性类型
Class<?> type = field[i].getType();
System.out.println(priv + " " + type.getName() + " "
+ field[i].getName() + ";");
}
System.out.println("===============实现的接口或者父类的属性========================");
// 取得实现的接口或者父类的属性
Field[] filed1 = demo.getFields();
for (int j = 0; j < filed1.length; j++) {
// 权限修饰符
int mo = filed1[j].getModifiers();
String priv = Modifier.toString(mo);
// 属性类型
Class<?> type = filed1[j].getType();
System.out.println(priv + " " + type.getName() + " "
+ filed1[j].getName() + ";");
}
}
}
【运行结果】:
===============本类属性========================
private java.lang.String sex;
===============实现的接口或者父类的属性========================
public static final java.lang.String name;
public static final int age;
【案例9】其实还可以通过反射调用其他类中的方法:
import java.lang.reflect.Method;
class hello {
public static void main(String[] args) {
Class<?> demo = null;
try {
demo = Class.forName("Reflect.Person");
} catch (Exception e) {
e.printStackTrace();
}
try {
//调用Person类中的sayChina方法
Method method = demo.getMethod("sayChina");
method.invoke(demo.newInstance());
//调用Person的sayHello方法
method = demo.getMethod("sayHello", String.class, int.class);
method.invoke(demo.newInstance(), "Rollen", 20);
} catch (Exception e) {
e.printStackTrace();
}
}
}
【运行结果】:
hello ,china
Rollen 20
【案例10】调用其他类的set和get方法
import java.lang.reflect.Method;
class hello {
public static void main(String[] args) {
Class<?> demo = null;
Object obj = null;
try {
demo = Class.forName("Reflect.Person");
} catch (Exception e) {
e.printStackTrace();
}
try {
obj = demo.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
setter(obj, "Sex", "男", String.class);
getter(obj, "Sex");
}
/**
* @param obj 操作的对象
* @param att 操作的属性
*/
public static void getter(Object obj, String att) {
try {
Method method = obj.getClass().getMethod("get" + att);
System.out.println(method.invoke(obj));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @param obj 操作的对象
* @param att 操作的属性
* @param value 设置的值
* @param type 参数的属性
*/
public static void setter(Object obj, String att, Object value, Class<?> type) {
try {
Method method = obj.getClass().getMethod("set" + att, type);
method.invoke(obj, value);
} catch (Exception e) {
e.printStackTrace();
}
}
}// end class
【运行结果】:
男
【案例11】通过反射操作属性
import java.lang.reflect.Field;
class hello {
public static void main(String[] args) throws Exception {
Class<?> demo = null;
Object obj = null;
demo = Class.forName("Reflect.Person");
obj = demo.newInstance();
Field field = demo.getDeclaredField("sex");
field.setAccessible(true);
field.set(obj, "男");
System.out.println(field.get(obj));
}
}// end class
【案例12】通过反射取得并修改数组的信息:
import java.lang.reflect.*;
class hello {
public static void main(String[] args) {
int[] temp = {1, 2, 3, 4, 5};
Class<?> demo = temp.getClass().getComponentType();
System.out.println("数组类型: " + demo.getName());
System.out.println("数组长度 " + Array.getLength(temp));
System.out.println("数组的第一个元素: " + Array.get(temp, 0));
Array.set(temp, 0, 100);
System.out.println("修改之后数组第一个元素为: " + Array.get(temp, 0));
}
}
【运行结果】:
数组类型: int
数组长度 5
数组的第一个元素: 1
修改之后数组第一个元素为: 100
【案例13】通过反射修改数组大小
import java.lang.reflect.Array;
class hello {
public static void main(String[] args) {
int[] temp = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int[] newTemp = (int[]) arrayInc(temp, 15);
print(newTemp);
System.out.println("=====================");
String[] atr = {"a", "b", "c"};
String[] str1 = (String[]) arrayInc(atr, 8);
print(str1);
}
/**
* 修改数组大小
*/
public static Object arrayInc(Object obj, int len) {
Class<?> arr = obj.getClass().getComponentType();
Object newArr = Array.newInstance(arr, len);
int co = Array.getLength(obj);
System.arraycopy(obj, 0, newArr, 0, co);
return newArr;
}
/**
* 打印
*/
public static void print(Object obj) {
Class<?> c = obj.getClass();
if (!c.isArray()) {
return;
}
System.out.println("数组长度为: " + Array.getLength(obj));
for (int i = 0; i < Array.getLength(obj); i++) {
System.out.print(Array.get(obj, i) + " ");
}
}
}
【运行结果】:
数组长度为: 15
1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 =====================
数组长度为: 8
a b c null null null null null