反射--简单入门讲解
一、反射的概述
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
反射的前提就是获取到类的字节码对象,有以下三种方式(以Student类来举例):
//第一种:通过类的路径来获取
Class<?> c1 = Class.forName("cn.tedu.reflection.Student");
//第二种:通过类名点class来获取
Class<?> c2 = Student.class;
//第三种:通过创建对象调用getClass方法来获取
Class<?> c3 = new Student().getClass();
注意:一般用第一种,第一种需要类填入路径,它是一个字符串,可以传入也可写在配置文件中等多种方法。第二种需要导入类的包,依赖太强,不导包就抛编译错误。第三种对象都有了还要反射作什么.......。
二、反射的实际操作以及API的使用
常用API:
Class<?> c1 = Class.forName("cn.tedu.reflection.Student");
System.out.println(c1);//打印字节码对象
System.out.println(c1.getName());//获取类的全路径名
System.out.println(c1.getSimpleName());//获取类名
System.out.println(c1.getPackage());//获取包对象
System.out.println(c1.getPackage().getName());//获取包名
实战用反射获取类里的内容:
普通反射:
1.创建物料类Student
package cn.tedu.jobo;
public class Student {
public String name;
public int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public void cool(){
System.out.println("coolboy 阎静辉");
}
public void like(String name,int age){
System.out.println("我老婆是:"+name+"她"+age+"岁了");
}
}
2.创建反射测试类进行内容获取
//构造方法
@Test
public void getConstrct(){
Class<Student> c = Student.class;
Constructor<?>[] constructors = c.getConstructors();
for (Constructor<?> con:
constructors) {
System.out.println(con.getName());
Class<?>[] parameterTypes = con.getParameterTypes();
System.out.println(Arrays.toString(parameterTypes));
}
}
//普通方法
@Test
public void getMethod(){
Class<Student> c = Student.class;
Method[] methods = c.getMethods();
for (Method m :
methods) {
System.out.println(m.getName());
Class<?>[] parameterTypes = m.getParameterTypes();
System.out.println(Arrays.toString(parameterTypes));
}
}
//成员变量
@Test
public void getFields(){
Class<Student> c = Student.class;
Field[] f = c.getFields();
for (Field i :
f) {
System.out.println(i.getName());
System.out.println(i.getType().getName());
}
}
//创建对象并调用方法
@Test
public void getnewInstance() throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class<Student> c = Student.class;
//无参
Student student = c.newInstance();
System.out.println(student);
//含参
Constructor<Student> cs = c.getConstructor(String.class,int.class);
Student zzf = cs.newInstance("张子枫", 19);
System.out.println(zzf);
System.out.println(zzf.age);
System.out.println(zzf.name);
zzf.cool();
zzf.like("张子枫", 19);
}
}
注意点:
1. 单元测试
好处:只涉及一个方法,使用灵活,方便
格式:@Test+public+void+无参
2.八大基本类型会直接显示,引用类型会显示全路径
3.通过含参构造来new对象需要先获取到这个指定的构造函数,且传入的参数必须是字节码对象
4.普通反射只能获取到public的方法和成员变量
暴力反射:
1.创建物料类Person
package cn.tedu.jobo;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
private void play(){
System.out.println("玩");
}
private void eat(String su,int n){
System.out.println("我喜欢吃:"+su+"我要吃"+n+"个");
}
}
2.创建暴力反射测试类进行内容获取
package cn.tedu.controller;
//暴力反射
import cn.tedu.jobo.Person;
import org.junit.Test;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
public class TestPerson {
//获取私有成员变量
@Test
public void getField() throws NoSuchFieldException, InstantiationException, IllegalAccessException {
Class<?> p = Person.class;
Field[] fs = p.getDeclaredFields();
for (Field f :
fs) {
System.out.println(f.getName());
System.out.println(f.getType().getName());
}
//设置成员变量
Field name = p.getDeclaredField("name");
name.setAccessible(true);
Object o = p.newInstance();
name.set(o, "阎静辉");
System.out.println(name.get(o));
}
//暴力反射获取使用私有方法
@Test
public void getMethod() throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Class<Person> p = Person.class;
Method[] declaredMethods = p.getDeclaredMethods();
for (Method d :
declaredMethods) {
System.out.println(d.getName());
Class<?>[] parameterTypes = d.getParameterTypes();
System.out.println(Arrays.toString(parameterTypes));
}
Method eat = p.getDeclaredMethod("eat", String.class, int.class);
eat.setAccessible(true);
Person person = p.newInstance();
eat.invoke(person,"米饭",1);
}
}
注意点:
1.Declared暴力反射时需要添加
2.暴力反射时需要手动设置私有资源可见的权限setAccessible(true)
3.set和invoke的区别使用
4.思想的转变:平常是通过对象名点属性获取值,反射就是反过来通过属性名点对象名和参数传入,通过方法名点哪个对象来执行加传入参数。
另外两种修饰符暴力反射获取
上述只讲了对于public和private权限修饰符的两种方法:普通反射和暴力反射的使用
对于另外两种默认(default)和protected权限修饰符同样可以用暴力反射来获取,示例如下:
1.物料类hhh
package cn.tedu.jobo;
public class hhh {
public String name;
protected int age;
double dog;
private char pig;
}
2.创建暴力反射测试类进行测试
package cn.tedu.controller;
import cn.tedu.jobo.hhh;
import org.junit.Test;
import java.lang.reflect.Field;
public class Testhhh {
@Test
public void getfields(){
Class<hhh> h = hhh.class;
Field[] declaredFields = h.getDeclaredFields();
for (Field f :
declaredFields) {
System.out.println(f);
}
}
}
3.结果如下
public java.lang.String cn.tedu.jobo.hhh.name
protected int cn.tedu.jobo.hhh.age
double cn.tedu.jobo.hhh.dog
private char cn.tedu.jobo.hhh.pig
兄弟盟,到这里就结束了,有不对的地方和需要补充的评论或者私信留言!
fighting!
fighting!!
fighting!!!
上一篇: 打印机突然停机维修一例