JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
反射实现的功能:
(1)在运行时判断任意一个对象所属的类。(2)在运行时构造任意一个类的对象。
(3)在运行时判断任意一个类所具有的成员变量和方法。
(4)在运行时调用任意一个对象的方法
前提是在运行时,不是编译时,也就是在运行前并不知道调用哪一个类,通过反射就可以做到这些 .
Java的类反射所需要的类并不多,它们分别是:Field、Constructor、Method、Class、Object,下面我将对这些类做一个简单的说明。
Field类:提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。这个类和Field类不同, Field类封装了反射类的属性,而Constructor类则封装了反射类的构造方法。
Method类:提供关于类或接口上单独某个方法的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。 这个类不难理解,它是用来封装反射类方法的一个类。
Class类:类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该Class 对象。
Object类:每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。
关于Java反射在工作中很少遇到,但是我们必须掌握它的原理以及它能为我们做什么,Spring框架的配置文件Bean就是以反射为基础实现的,下面我们以案例为主看看反射的API能带给我们什么。
①获取类的Class对象:
package Reflection;
class Demo{}
public class GetClassName {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> cls1=Demo.class;
Class<?> cls2=Class.forName("Reflection.Demo");//常用模式,注意类名是全限定名
Class<?> cls3=new Demo().getClass();
System.out.println(cls1.getName()+"---------"+cls2.getName()+"---------"+cls3.getName());
}
}
②实例化Class
package Reflection;
class Student{
private String name;
private String age;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
public class GetInstanceByClass {
public static void main(String[] args){
try {
Class cls=Class.forName("Reflection.Student");
Student student=(Student) cls.newInstance();
student.setName("小明");
student.setAge("12");
student.setSex("男");
System.out.println(student.getName()+"是"+student.getAge()+"岁的"+student.getSex()+"孩");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
③通过构造器实例化Class
以下实例注意两点:
1.创建类的时候,如果未定义任何构造函数,系统会自动为类默认一个无参构造函数,如果自己定义了有参构造器,那么无参构造函数将不会生成,这种情况下调用类的无参构造函数会报错,因此需要自定义无参构造函数。
2.Class的getConstructors()方法返回构造函数数组顺序与在类中定义的顺序不是一致的,因此先打印出来看一下,我们可以用Constructor类的getParameterTypes()获取该构造方法的参数
package Reflection;
import java.lang.reflect.Constructor;
class Student{
private String name;
private String age;
private String sex;
public Student() {}
public Student(String name) {
this.name = name;
}
public Student(String name, String age) {
this.name = name;
this.age = age;
}
public Student(String name, String age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
public class GetInstanceByClass {
public static void main(String[] args){
try {
Class cls=Class.forName("Reflection.Student");
Constructor<?> cons[]=cls.getConstructors();
for(Constructor c:cons) {
System.out.println(c);
}
Student student1=(Student) cons[0].newInstance("小明","12","男");
Student student2=(Student) cons[1].newInstance("小明","12");
Student student3=(Student) cons[2].newInstance("小明");
Student student4=(Student) cons[3].newInstance();
student4.setName("小明");
student4.setAge("12");
student4.setSex("男");
System.out.println(student1.getName()+"是"+student1.getAge()+"岁的"+student1.getSex()+"孩");
System.out.println(student2.getName()+"是"+student2.getAge()+"岁的"+student2.getSex()+"孩");
System.out.println(student3.getName()+"是"+student3.getAge()+"岁的"+student3.getSex()+"孩");
System.out.println(student4.getName()+"是"+student4.getAge()+"岁的"+student4.getSex()+"孩");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
④获取类的父类以及实现的接口
我们知道一个类只能继承一个父类,但可以实现多个接口,因此父类返回的是对象,接口方法返回的是对象数组。
package Reflection;
class School{
public String schoolname="翡翠小学";
}
interface Study{
public String studyMethod();
public String studyGrade();
}
class Student extends School implements Study{
private String name;
private String age;
private String sex;
public Student() {}
public Student(String name) {
this.name = name;
}
public Student(String name, String age) {
this.name = name;
this.age = age;
}
public Student(String name, String age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String studyMethod() {
return "多做练习,多背诵";
}
@Override
public String studyGrade() {
return "优秀";
}
}
public class GetSuperClassAndInterface {
public static void main(String[] args) {
try {
Class cls=Class.forName("Reflection.Student");
Class<?> inters[]=cls.getInterfaces();//获取Student的所有接口
Class<?> superclass=cls.getSuperclass();//获取Student所有父类
for(Class s:inters){
System.out.println("实现的接口"+s.getName());
}
System.out.println("继承的父类"+superclass.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
⑤获取一个类的全部属性
这 里用到了两个方法,getFields()、getDeclaredFields(),它们分别是用来获取反射类中所有公有属性和反射类中所有的属性的方 法。另外还有getField(String)和getDeclaredField(String)方法都是用来过去反射类中指定的属性的方法,要注意的 是getField方法只能取到反射类中公有的属性,而getDeclaredField方法都能取到。
这里还用到了Field 类的setAccessible方法,它是用来设置是否有权限访问反射类中的私有属性的,只有设置为true时才可以访问,默认为false。另外 Field类还有set(Object AttributeName,Object value)方法,可以改变指定属性的值。
package Reflection;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
class Student{
public String name;
private String age;
public String sex;
private String girlfriend="小红";
private String mistress="小丽";
public Student() {}
public Student(String name) {
this.name = name;
}
public Student(String name, String age) {
this.name = name;
this.age = age;
}
public Student(String name, String age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
public class GetFiled {
public static void main(String[] args) {
try {
Class cls=Class.forName("Reflection.Student");
//获取公有属性
Field[] pf=cls.getFields();
//这里e.getModifiers()返回修饰符是整型需要通过静态方法转换,e.getType()获取返回类型
for(Field e:pf){
System.out.println(Modifier.toString(e.getModifiers())+" "+e.getType()+" "+e.getName());
}
//获取所有属性
Field[] af=cls.getDeclaredFields();
for(Field e:af){
System.out.println(Modifier.toString(e.getModifiers())+" "+e.getType()+" "+e.getName());
}
//反射类中的某个私有类,并从对象中获取该属性值也可以将该对象的私有属性值修改
Student student=(Student) cls.newInstance();
Field mistress=cls.getDeclaredField("mistress");
mistress.setAccessible(true);
String mistressname=(String) mistress.get(student);
System.out.println(mistressname);
mistress.set(student,"莉莉");
System.out.println(mistress.get(student));
} catch (Exception e) {
e.printStackTrace();
}
}
}
⑥获取一个类的所有方法
这里所有方法包含从父类继承的方法,我们看看实例。
public Method[] getMethods()返回某个类的所有公用(public)方法包括其继承类的公用方法,当然也包括它所实现接口的方法。public Method[] getDeclaredMethods()对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所实现接口的方法。
package Reflection;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
class School{
public void getTeacher(String name){
System.out.println("班主任是"+name);
}
private void getSchoolMaster(String name){
System.out.println("校长是"+name);
}
public String getDeskMate(String name){
return name;
}
}
class Student extends School{
public String studyMethod() {
return "多做练习,多背诵";
}
private void studyGrade() {
System.out.println("成绩优秀");
}
public void getCrush(String name){
System.out.println("暗恋"+name);
}
}
public class GetMethods {
public static void main(String[] args) {
try {
Class cls=Class.forName("Reflection.Student");
//返回某个类的所有公用(public)方法包括其继承类的公用方法,当然也包括它所实现接口的方法
Method[] pms=cls.getMethods();
for(Method m:pms){
System.out.println("私有方法:"+Modifier.toString(m.getModifiers())+" "+m.getReturnType()+" "+m.getName());
}
//对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所实现接口的方法
Method[] ams=cls.getDeclaredMethods();
for(Method m:ams){
System.out.println("所有方法:"+Modifier.toString(m.getModifiers())+" "+m.getReturnType()+" "+m.getName());
}
//通过反射调用方法
Method method=cls.getMethod("getCrush", String.class);
method.invoke(cls.newInstance(), "小青");
//调用父类的公有方法
Method supermethod=cls.getMethod("getTeacher", String.class);
supermethod.invoke(cls.newInstance(), "林老师");
//返回名称为studyGrade的私有方法
Method privatemethodself=cls.getDeclaredMethod("studyGrade");
privatemethodself.setAccessible(true);
privatemethodself.invoke(cls.newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
}
⑦反射读取数组信息
package Reflection;
import java.lang.reflect.Array;
public class ArrayReflection {
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));
}
}
以上是反射的基本运用,对于反射实现动态代理以及用于工厂模式,请查看我的另一篇博文,静态代理与动态代理的区别。
转载于:https://blog.51cto.com/zangyanan/1841097