反射简单来说,就是动态加载对象,并对对象进行剖析。在Java中的反射机制是指在运行状态中,对于任意一个类,都能够知道并获取这个类的所有属性和方法。
Java反射机制的作用:
- 在运行时判断任意一个对象所属的类。
- 在运行时判断任意一个类所具有的成员变量和方法。
- 在运行时任意调用一个对象的方法
- 在运行时构造任意一个类的对象
反射机制的优缺点是什么?
反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性。
它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它
满足我们的要求。这类操作总是慢于只直接执行相同的操作。
获取Class对象的三种方式
package com.gyl;
public class Student {
public int no;
public String sex;
private String name;
private int 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;
}
/*
* 构造方法
*/
Student(String str){
System.out.println("(默认)的构造方法 s = " + str);
}
//无参构造方法
public Student(){
System.out.println("调用了公有、无参构造方法执行了。。。");
}
//有一个参数的构造方法
protected Student(char name){
System.out.println("姓名:" + name);
}
//有多个参数的构造方法
public Student(String name ,int age){
System.out.println("姓名:"+name+"年龄:"+ age);//这的执行效率有问题,以后解决。
}
//私有构造方法
private Student(int age){
System.out.println("私有的构造方法 年龄:"+ age);
}
}
package com.gyl;
import java.lang.reflect.Constructor;
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
Student student = new Student();
/*
* JAVA反射--获取Class对象的三种方式
*/
// 通过对象名.getClass()方法获取
Class stuClass = student.getClass();
System.out.println("stuClass is "+stuClass.getName());
// 通过类名.class方式获得
Class stuClass1 = Student.class;
System.out.println("stuClass1 is "+stuClass1.getName());
System.out.println(stuClass == stuClass1);
// 通过Class.forName()方法获得
Class stuClass2 = Class.forName("com.gyl.Student");
System.out.println("stuClass2 is "+stuClass2);
System.out.println(stuClass1 == stuClass2);
}
}
Output:
stuClass is com.gyl.Student
stuClass1 is com.gyl.Student
true
stuClass2 is class com.gyl.Student
true
在运行期间,一个类,只有一个Class对象产生。三种方式常用第三种,第一种对象都有了还要反射干什么。第二种需要导入类的包,依赖太强,不导包就抛编译错误。一般都选第三种,一个字符串可以传入也可写在配置文件中等多种方法。
反射API
获取构造方法
// 返回指定参数类型 public的构造器。
Constructor<T> getConstructor(类<?>... parameterTypes)
// 返回指定参数类型的构造器(public, protected, private)。
Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
// 返回所有的public类型的构造器
Constructor<?>[] getConstructors()
// 返回所有的构造器
Constructor<?>[] getDeclaredConstructors()
package com.gyl;
import java.lang.reflect.Constructor;
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
// 通过Class.forName()方法获得Class对象
Class stuClass = Class.forName("com.gyl.Student");
System.out.println("************返回所有public构造方法************");
Constructor[] constructors = stuClass.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
/*
* Output:
* ************返回所有public构造方法************
* public com.gyl.Student()
* public com.gyl.Student(java.lang.String,int)
*/
System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
Constructor[] constructors2 = stuClass.getDeclaredConstructors();
for (Constructor constructor : constructors2) {
System.out.println(constructor);
}
/*
* Output:
* ************所有的构造方法(包括:私有、受保护、默认、公有)***************
* private com.gyl.Student(int)
* public com.gyl.Student()
* protected com.gyl.Student(char)
* public com.gyl.Student(java.lang.String,int)
* com.gyl.Student(java.lang.String)
*/
Constructor constructor;
System.out.println("************返回指定类型的 public构造器************");
try {
constructor = stuClass.getConstructor(String.class, int.class);
System.out.println(constructor);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
/*
* Output:
* ************返回指定类型的 public构造器************
* public com.gyl.Student(java.lang.String,int)
*
* 如果指定参数的构造器是非public类型的 则抛出java.lang.NoSuchMethodException异常
*/
System.out.println("************返回指定类型的构造器************");
try {
constructor = stuClass.getDeclaredConstructor(int.class);
System.out.println(constructor); // char.class
} catch (NoSuchMethodException e) { // String.class, int.class
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
/*
* Output:
* ************返回指定类型的构造器************
* public com.gyl.Student(java.lang.String,int)
* protected com.gyl.Student(char)
* private com.gyl.Student(int)
*/
}
}
获取变量
// 根据变量名获得对应的变量,访问权限不限;
Field getDeclaredField(String name)
// 获得类中所有属性变量
Field[] getDeclaredFields()
// 根据变量名获取对应public类型的属性变量
Field getField(String name)
// 获取类中所有public类型的属性变量
Field[] getFields()
package com.gyl;
import java.lang.reflect.Field;
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
// 通过Class.forName()方法获得Class对象
Class stuClass = Class.forName("com.gyl.Student");
try {
Field field1 = stuClass.getField("sex");
System.out.println(field1);
Field field = stuClass.getDeclaredField("name");
System.out.println(field);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
/*
* Output:
* public java.lang.String com.gyl.Student.sex
* private java.lang.String com.gyl.Student.name
* 如果使用getField方法指定了一个非public类型的属性,则抛出java.lang.NoSuchFieldException异常
*/
Field[] fields1 = stuClass.getFields();
Field[] fields = stuClass.getDeclaredFields();
System.out.println("************返回所有public属性************");
for (Field field : fields1) {
System.out.println(field);
}
/*
* Output:
* ************返回所有public属性************
* public int com.gyl.Student.no
* public java.lang.String com.gyl.Student.sex
*/
System.out.println("************返回所有属性************");
for (Field field : fields) {
System.out.println(field);
}
/*
* Output:
* ************返回所有属性************
* public int com.gyl.Student.no
* public java.lang.String com.gyl.Student.sex
* private java.lang.String com.gyl.Student.name
* private int com.gyl.Student.age
*/
}
}
获取方法
// 获取“名称是name,参数是parameterTypes”的public的函数(包括从基类继承的、从接口实现的所有public函数)
public Method getMethod(String name, Class[] parameterTypes)
// 获取全部的public的函数(包括从基类继承的、从接口实现的所有public函数)
public Method[] getMethods()
// 获取“名称是name,参数是parameterTypes”,并且是类自身声明的函数,包含public、protected和private方法。
public Method getDeclaredMethod(String name, Class[] parameterTypes)
// 获取全部的类自身声明的函数,包含public、protected和private方法。
public Method[] getDeclaredMethods()
// 如果这个类是“其它类中某个方法的内部类”,调用getEnclosingMethod()就是这个类所在的方法;若不存在,返回null。
public Method getEnclosingMethod()
package com.gyl;
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
// 通过Class.forName()方法获得Class对象
Class stuClass = Class.forName("com.gyl.Student");
Method method;
try {
// method = stuClass.getMethod("getName");
method = stuClass.getDeclaredMethod("getAge");
System.out.println(method);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
System.out.println("*********输出所有方法********");
Method[] methods = stuClass.getDeclaredMethods();
for (Method method2 : methods) {
System.out.println(method2);
}
/*
* Output:
* public int com.gyl.Student.getAge()
* *********输出所有方法********
* public java.lang.String com.gyl.Student.getName()
* public void com.gyl.Student.setName(java.lang.String)
* void com.gyl.Student.print(java.lang.String)
* public int com.gyl.Student.getAge()
* public void com.gyl.Student.setAge(int)
*/
}
}
通过反射越过泛型检查
泛型用在编译期,编译过后泛型擦除(消失掉)。所以是可以通过反射越过泛型检查的
import java.lang.reflect.Method;
import java.util.ArrayList;
/*
* 通过反射越过泛型检查
*
* 例如:有一个String泛型的集合,怎样能向这个集合中添加一个Integer类型的值?
*/
public class Demo {
public static void main(String[] args) throws Exception{
ArrayList<String> strList = new ArrayList<>();
strList.add("aaa");
strList.add("bbb");
// strList.add(100);
//获取ArrayList的Class对象,反向的调用add()方法,添加数据
Class listClass = strList.getClass(); //得到 strList 对象的字节码 对象
//获取add()方法
Method m = listClass.getMethod("add", Object.class);
//调用add()方法
m.invoke(strList, 100);
//遍历集合
for(Object obj : strList){
System.out.println(obj);
System.out.println(obj.getClass());
}
/*
*Output:
* aaa
* class java.lang.String
* bbb
* class java.lang.String
* 100
* class java.lang.Integer
*/
}
}
其他方法请参考Java jdk,本文参考自Java jdk1.8