一.反射定义
在运行期间,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的属性和方法,让对象认识到自身的结构。
二.反射实质
就是把JAVA类中的各种成分映射成一个个的JAVA对象
当我们new Student时,jvm会加载Student.class文件,jvm会去我们本地磁盘找Student.class文件,并加载到jvm内存中,一个类只产生一个class对象。
反射的本质就是得到class对象后,反向获取Student对象的各种信息
三.反射的使用
首先建一个User类
public class User {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
public User() {
}
}
1.获取对象的类型
方式一.
Object.getClass() //获取方法属性首先应获取对象类型
方式二
Class.forName() //根据类型名字获取对象类型,注意类型名前要加上包名
方式三.
类名.class
public static void main(String[] args) throws ClassNotFoundException {
//方式一
System.out.println(new User().getClass());
//方式二
Class<?> aClass = Class.forName("reflectTest.User");//带包名的类路径,包名.类名
System.out.println(aClass);
//这个类型信息在jvm仍表现为一个对象,而且只有一份,判断第一种方式获取的Class对象和第二种方式获取的是否是同一个,结果为true,证明是同一对象
System.out.println(new User().getClass()==Class.forName("reflectTest.User"));
//方式三
System.out.println(User.class);
}
在运行期间,一个类,只有一个Class对象产生,常用第二种方法
2.类对象功能
(1).用反射方式创建对象
正常创建对象:new 类名();
反射创建对象:类对象.newInstance();
通过类对象创建一个实例,限制条件:要求对象有无参构造,且构造方法不能是私有的
User user = User.class.newInstance();
System.out.println(user);
(2)获取方法信息
1.批量的:
-
public Method[] getMethods():获取所有"公有方法"(public),返回Method[]数组,(包含了父类的方法也包含Object类)
类对象.getMethods();
-
public Method[] getDeclaredMethods():获取本类所有的成员方法,包括(public,private,protected,不加)(不包括继承的)
2.获取单个的:
-
public Method getMethod(String name,Class<?>... parameterTypes): 参数:name : 方法名;Class ... : 形参参数类型
-
public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
public class User {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
public User() {
}
//**************成员方法***************//
public void show1(String s){
System.out.println("调用了:公有的,String参数的show1(): s = " + s);
}
protected void show2(){
System.out.println("调用了:受保护的,无参的show2()");
}
void show3(){
System.out.println("调用了:默认的,无参的show3()");
}
private String show4(int age){
System.out.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " + age);
return "abcd";
}
public void m1(int a, int b) {
System.out.println("m1(int a, int b)被执行");
}
private void m1() {
System.out.println("m1被执行");
}
}
System.out.println("调用所有公共方法");
Class<?> aClass = Class.forName("reflectTest.User");
Method[] methods = aClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("调用所有方法");
Method[] methods1 = aClass.getDeclaredMethods();
for (Method method : methods1) {
System.out.println(methods1);
}
System.out.println("获取单个公共show1方法");
Method show1 = aClass.getMethod("show1", String.class);
System.out.println(show1);
System.out.println("获取私有show4方法");
Method show4 = aClass.getDeclaredMethod("show4", int.class);
System.out.println(show4);
System.out.println("获取多个形参公共方法");
Method m1 = aClass.getMethod("m1", int.class, int.class);
System.out.println(m1);
System.out.println("无参方法");
Method m11 = aClass.getDeclaredMethod("m1");
System.out.println(m11);
(3).获取属性信息
a.类对象.getFields(); //获取 所有的公共属性,包括继承的,返回Field[]数组
b.类对象.getDeclaredFields() ; //获取本类所有属性(public,private,protected,不加)
c.类对象.getField(“属性名”) //获取某个公共属性
d.类对象.getDeclaredField(“属性名”) //获取某个属性(public,private,protected,不加)
e.设置字段的值:
Field --> public void set(Object obj,Object value):
参数说明:
1.obj:要设置的字段所在的对象;
应先获取对象
Object o = aClass.getConstructor().newInstance();//获取对象
2.value:要为字段设置的值;
public class Student {
public Student(){
}
//**********字段*************//
public String name;
protected int age;
char sex;
private String phoneNum;
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", sex=" + sex
+ ", phoneNum=" + phoneNum + "]";
}
}
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> aClass = Class.forName("reflectTest.Student");
System.out.println("获取所有公共属性");
Field[] fields = aClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("获取所有属性");
Field[] fields1 = aClass.getDeclaredFields();
for (Field field1 : fields1) {
System.out.println(field1);
}
System.out.println("获取公共属性name");
Field name = aClass.getField("name");
System.out.println(name);
Object o = aClass.getConstructor().newInstance();//获取对象,需创建无参构造
name.set(o,"张小雨");///为Student对象中的name属性赋值--》stu.name = "XXX“”
Student stu=(Student)o;
System.out.println(stu.name);
System.out.println("获取私有属性");
Field phoneNum = aClass.getDeclaredField("phoneNum");
System.out.println(phoneNum);
phoneNum.setAccessible(true);//暴力反射,解除私有限定
phoneNum.set(o, "18888889999");
System.out.println(stu);//私有属性需get/set方法
}
(4).获取构造方法
1).批量的方法:
类对象.getConstructors():所有"公有的"构造方法,返回Constructor[]数组
类对象.getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有的
2).获取单个的方法,并调用:
类对象.getConstructor(Class… parameterTypes):获取单个的"公有的"构造方法:
类对象. getDeclaredConstructor(Class… parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
//(默认的构造方法)
Student(String str){
System.out.println("(默认)的构造方法 s = " + str);
}
//无参构造方法
public Student(){
System.out.println("调用了公有、无参构造方法执行了。。。");
}
//有一个参数的构造方法
public Student(char name){
System.out.println("姓名:" + name);
}
//有多个参数的构造方法
public Student(String name ,int age){
System.out.println("姓名:"+name+"年龄:"+ age);//这的执行效率有问题,以后解决。
}
//受保护的构造方法
protected Student(boolean n){
System.out.println("受保护的构造方法 n = " + n);
}
//私有构造方法
private Student(int age){
System.out.println("私有的构造方法 年龄:"+ age);
}
System.out.println("获取所有构造方法");
Constructor[] constructors = aClass.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("获取所有构造方法");
Constructor[] constructors1 = aClass.getDeclaredConstructors();
for (Constructor constructor11 : constructors1) {
System.out.println(constructor11);
}
System.out.println("获取公有、无参的构造方法");
Constructor constructor2= aClass.getConstructor();
System.out.println(constructor2);
//调用构造方法
Object obj = constructor2.newInstance();
System.out.println("obj = " + obj);
Student stu1 = (Student)obj;
System.out.println(stu1);
System.out.println("获取私有构造方法");
Constructor constructor3 = aClass.getDeclaredConstructor(int.class);
System.out.println(constructor3);
constructor3.setAccessible(true);
constructor3.newInstance(28);
System.out.println(stu1.age);
(5).反射调用方法
正常调用:对象.方法名(参数)
反射调用:方法.invoke(对象,参数)//方法在哪个对象上执行
User u = new User();
// 方法.invoke(对象, 参数);
Method m = User.class.getDeclaredMethod("m1");
m.setAccessible(true); // 设置这个方法可以被访问,可以突破访问修饰符的限制
m.invoke(u); // 反射调用方法(性能低)
// 反射调用 public void m1(int a)
Method m12 = User.class.getDeclaredMethod("m1", int.class);
m12.invoke(u, 1);
Method m13 = User.class.getDeclaredMethod("m1", int.class, int.class);
m13.invoke(u, 4, 5);
反射调用缺点:调用复杂,效率极低
优点:可以访问私有方法,突破正常方法的限制
私有方法
private Student() {
System.out.println("私有构造被调用");
}
// 调用私有构造
Constructor<Student> cons = Student.class.getDeclaredConstructor();
cons.setAccessible(true);
Student s = cons.newInstance();
System.out.println(s);
三.类加载器
加载一个不再classPath下的类
ClassLoader cl = new ClassLoader() {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
FileInputStream in = new FileInputStream("F:\\JAVAclass\\day201201_1\\Treasure.class");
byte[] bytes = new byte[1024*8];
int len = in.read(bytes);
// 调用父类的方法根据字节数组加载类
return defineClass(name, bytes, 0, len);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
};
Class<?> clazz = cl.loadClass("com.westos.Treasure"); // 根据类名加载类, 得到类对象
Constructor<?> constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
Object o = constructor.newInstance();//私有构造获取对象,可以进一步获取方法