反射:
反射就是通过获取Class字节码文件对象/Classs的类对象,获取该字节码文件对象中的成员变量,构造方法,和成员方法
Field类: 简称成员变量 (Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限,反射的字段可能是一个类(静态)字段或实例字段。)
Constructor:简称构造方法:提供关于类的单个构造方法的信息以及对它的访问权限。
Method:简称成员方法:类或接口上单独某个方法(以及如何访问该方法)的信息
面试题:
如何获取class字节码文件对象/Class的类对象
三种方式来获取这个class字节码文件对象:
1)Object中的getClass()
2)任何数据类型的静态属性class
3)Class类中的方法:
forName(String className)
forName("类路径")
在开发中一般使用第三种方法,如果自己写的话,第一二种方法就可以解决
下面我们来看看例子:
package com.westos.Reflect;
public class personDome {
//创建personDome类的无参构造
public personDome () {
}
}
package com.westos.Reflect;
public class ReflectDome {
public static void main(String[] args) throws ClassNotFoundException {
//创建Person类对象
personDome p1=new personDome();
personDome p2=new personDome();
//方法1:调用方法名.getclass()方法获取字节码文件
Class c1 = p1.getClass();
Class c2 = p2.getClass();
System.out.println(c1);
System.out.println(c2);
System.out.println(p1==p2);
System.out.println(c1==c2);
System.out.println("--------------------------");
//方法2:调用类中的静态属性class去获取字节码文件
Class c3 = personDome.class;
System.out.println(c3==c2);
System.out.println("---------------------------");
//方法3:调用Class类中forName(类路径)方法去获取
Class c4 = Class.forName("com.westos.Reflect.personDome");
System.out.println(c4==c2);
}
}
运行结果:
class com.westos.Reflect.personDome
class com.westos.Reflect.personDome
false
true
--------------------------
true
---------------------------
True
从上面的运行结果我们可以看出,创建的了两个personDome类对象但是返回的class字节码文件却是一样的,所以我们无论运用以上的哪种方法,personDome类中返回的字节码文件只有一个
1.下面让我们通过反射来获取无参构造方法并创建类的实例对象:
package com.westos.Reflect02;
public class Person {
/**
* 创建成员变量
*/
//创建一个带私有修饰的name变量
private String name;
//创建一个没有修饰符的age变量
int age;
//创建一个公共访问的address变量
public String address;
/**
* 创建构造方法
*/
//创建一个公共的无参构造
public Person() {
}
//创建一个私有的带一个参数的构造方法
private Person(String name) {
this.name=name;
}
//创建一个不带修饰符带两个参数的构造方法
Person(String name,int age){
this.name=name;
this.age=age;
}
//创建一个公共访问的带三个参数的构造方法
public Person (String name,int age,String address) {
this.name=name;
this.age=age;
this.address=address;
}
/**
* 创建成员方法
*/
//创建一个无参没有返回值的方法
public void show(){
System.out.println("show方法");
}
//创建一个有参没返回值的方法
public void method(String s) {
System.out.println("method方法");
}
//创建一个有参有返回值的方法
public String getPerson(String s,int i) {
return s+i;
}
//创建一个私有的无参无返回值的方法
public void getprivate() {
System.out.println("getprivate方法");
}
//重写toString方法
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", address=" + address + "]";
}
}
package com.westos.Reflect02;
import java.lang.reflect.Constructor;
/**
* 通过字节码文件对象获取构造方法(Constructors)并使用
*
*/
public class ReflectDome {
public static void main(String[] args) throws Exception {
//1)获取Person类的字节码文件对象
Class c=Class.forName("com.westos.Reflect02.Person");
/**
* 2)获取该类中的所有公共构造方法:
* public Constructor<?>[] getConstructors()
*/
Constructor[] cons = c.getConstructors();
//for循环
for(Constructor con:cons) {
System.out.println("getConstructors(): "+con);
}
System.out.println("------------------------------------------------------");
/**
* 3)获取该类中所有的构造方法(包括私有构造、公共的、没修饰的):
* public Constructor<?>[] getDeclaredConstructors()
*/
Constructor[] cons2 = c.getDeclaredConstructors();
for(Constructor con2:cons2) {
System.out.println("getDeclaredConstructors(): "+con2);
}
System.out.println("------------------------------------------------------");
/**
* 4)想要获取单个的构造方法应该怎么做?
* 这里应该注意上面的获取所有的公共构造方法(Constructors)和这里的获取单个构造方法(Constructors)的区别
* 前者比后者多了个s,这个要区分好
* public Constructor<T> getConstructor(Class<?>... parameterTypes)
*/
//这里是无参的话,括号里可以不用写
Constructor con3= c.getConstructor();
System.out.println("getConstructor(): "+con3);
//表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例
Object obj = con3.newInstance();
System.out.println("newInstance(): "+obj);
}
}
运行结果:
getConstructors(): public com.westos.Reflect02.Person(java.lang.String,int,java.lang.String)
getConstructors(): public com.westos.Reflect02.Person()
------------------------------------------------------
getDeclaredConstructors(): public com.westos.Reflect02.Person(java.lang.String,int,java.lang.String)
getDeclaredConstructors(): com.westos.Reflect02.Person(java.lang.String,int)
getDeclaredConstructors(): private com.westos.Reflect02.Person(java.lang.String)
getDeclaredConstructors(): public com.westos.Reflect02.Person()
------------------------------------------------------
getConstructor(): public com.westos.Reflect02.Person()
newInstance(): Person [name=null, age=0, address=null]
3. 通过反射来获取私有的有参构造并创建类的实例对象
package com.westos.Reflect02;
import java.lang.reflect.Constructor;
/**
* 访问私有构造方法并使用
*
*/
public class ReflectDome3 {
public static void main(String[] args) throws Exception {
//1)创建Person类的字节码文件对象
Class c = Class.forName("com.westos.Reflect02.Person");
//2)获取私有构造方法
Constructor con = c.getDeclaredConstructor(String.class);
/**
* 因为上面的构造方法时私有的,java语言访问时不允许创建类的实例对象
* 在运行的时候会出现异常,所以我们需要一个方法去强制取消java语言的访问检查
* public void setAccessible(boolean flag)
* 其中flag值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查
*/
con.setAccessible(true);
//3)调用newInstance方法
Object obj = con.newInstance("迪丽热巴");
System.out.println(obj);
}
}
运行结果:
Person [name=迪丽热巴, age=0, address=null]
上面我们了解了如何通过反射获取构造方法并创建类的实例对象,下面我们再来了解一下如何通过反射获取成员变量并想类的实例对象中的属性赋值:
package com.westos.Reflect03;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
/**
* 通过反射获取成员变量(Field)并创建实例对象
*
*/
public class ReflectDome {
public static void main(String[] args) throws Exception {
//创建Person类的class类的字节码文件对象
Class c = Class.forName("com.westos.Reflect02.Person");
//获取所有的公共成员变量
Field[] fields = c.getFields();
for(Field field:fields) {
System.out.println("getFields(): "+field);
}
System.out.println("--------------------------------------------");
/**
* 获取公共的成员变量并赋值
* 首先先得获取公共的构造方法,
* 然后通过Field类中的方法去赋值:public void set(Object obj,Object value)
*/
//这里访问的都是公共的无参构造方法
Constructor con = c.getConstructor();
Object obj = con.newInstance();
Field fie= c.getField("address");
fie.set(obj, "子长");
System.out.println(obj);
/**
* 当我们想要获取私有的成员变量并想赋值时
* 因为上面已经创建了无参构造方法,所以我们这里不需要去创建,直接访问上面的构造方法即可
*/
//访问私有的成员变量
/**
* private Person(String name) {
this.name=name;
}
*/
Field fie2 = c.getDeclaredField("name");
//因为name是私有属性,所以需要取消java语言访问检查
fie2.setAccessible(true);
fie2.set(obj, "杰哥");
System.out.println(obj);
/**
* 让我们给没有修饰符的成员变量赋值
*/
//同样运行getDeclaredField方法
Field fie3 = c.getDeclaredField("age");
//取消java语言的访问检查
fie3.setAccessible(true);
//赋值
fie3.set(obj, 22);
System.out.println(obj);
}
}
运行结果:
getFields(): public java.lang.String com.westos.Reflect02.Person.address
--------------------------------------------
Person [name=null, age=0, address=子长]
Person [name=杰哥, age=0, address=子长]
Person [name=杰哥, age=22, address=子长]
上面我们了解通过反射获取成员变量、构造方法,接下来看看如何获取成员方法并使用
package com.westos.Reflect03;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* 通过反射获取当前类的成员方法并使用
*
*/
public class ReflectDome2 {
public static void main(String[] args) throws Exception {
//创建Person类的字节码文件对象
Class c = Class.forName("com.westos.Reflect02.Person");
/**
* 获取所有的成员方法,包括该类以及父类的所有成员方法
* public Method[] getDeclaredMethods():所有的成员方法
*/
Method[] m1 = c.getMethods();
for(Method m:m1) {
// System.out.println(m);
}
//获取该类的无参构造
Constructor con = c.getConstructor();
Object obj = con.newInstance();
//获取该类的成员方法show
/*public void show(){
System.out.println("show方法");
}
*/
Method m2 = c.getMethod("show");
//public Object invoke(Object obj, Object... args)
m2.invoke(obj);//因为该方法是无参方法
System.out.println("--------------------------");
//获取该类的成员方法method
/*public void method(String s) {
System.out.println("method方法");
}
*/
Method m3 = c.getMethod("method", String.class);
m3.invoke(obj, "baby");
System.out.println("-----------------------------");
//获取成员方法getPerson
/*public String getPerson(String s,int i) {
return s+i;
}
*/
Method m4 = c.getMethod("getPerson", String.class,int.class);
Object ob = m4.invoke(obj,"格力",30);
System.out.println(ob);
System.out.println("-----------------------------");
//获取成员方法
/*private void getprivate() {
System.out.println("getprivate方法");
}
*/
//这里应该获取私有的成员方法,需要调用getDeclaredMethod方法
Method m5 = c.getDeclaredMethod("getprivate");
//取消java语言访问检查
m5.setAccessible(true);
m5.invoke(obj);
}
}
运行结果:
show方法
--------------------------
method方法baby
-----------------------------
格力30
-----------------------------
getprivate方法
package com.westos.Reflect04;
/**
* 我们可以自定义创建一个方法通过反射向成员变量赋值
*/
import java.lang.reflect.Field;
public class Tool {
public void setProperty(Object obj,String propertyName,Object value) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
//获取当前类的字节码文件
Class c = obj.getClass();
//当我们不知道成员变量的权限修饰,用public Field getDeclaredField(String name)
Field f = c.getDeclaredField(propertyName);
//取消java的语言访问检查
f.setAccessible(true);
//赋值
f.set(obj,value);
}
}