1.在说反射之前,先说说Class类.我们所写的类在加载前都会把Class类加载到jvm中,保存Java类的信息,而Class对象的由来是jvm在.class文件中找到并加载到jvm内存中,然后在为之创建一个Class对象.比如Person类,就会有一个对应的Class对象Person,但是这个Class类对象每个类只有一个.即一个类只有一个类对象,可以有多个对象.
2.反射的概念:反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。.通俗说就是将类的各个组成部分封装成其他对象。
好处:1.可以在程序的运行过程中,操作这些对象。
2.可以解耦,提高程序的可扩展性。
3.获取类 对象 DemoA.java
package fanshe;
//获取类 对象
public class DemoA {
//同一个字节码文件在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个
public static void main(String[] args) {
try{
//对应第一阶段:Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
//多用于配置文件,将类名定义在配置文件中。读取文件,加载类
Class c1 = Class.forName("fanshe.Person");//第一种方式(推荐) 包名.类名
//对应第二阶段:类名.class:通过类名的属性class获取
//多用于参数的传递
Class c3 = Person.class;//第二种方式
//对应第三阶段:对象.getClass():通过方法来获取
//多用于对象的获取字节码
Class c2 = new Person().getClass();//第三种方式
Class c4 = Integer.TYPE;//第四种方式 特有方式 只有原始数据类型有 得到int
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
}catch(Exception e){
System.out.println(e.getMessage());
}
}
4.获取对象 DemoB.java
package fanshe;
import java.lang.reflect.Constructor;
//获取对象(构造器)
public class DemoB {
public static void a(){
try{
Class c1 = Class.forName("fanshe.Person");
//通过无参构造器来初始化对象
Object obj = c1.newInstance();
System.out.println(obj);
}catch(Exception e){
System.out.println(e.getMessage());
}
}
public static void b(){
try{
Class c1 = Class.forName("fanshe.Person");
Class[] 形式参数列表 = {};
Constructor constructor = c1.getConstructor(形式参数列表);//得到形式参数列表对应的构造器
Object[] 实际参数列表 = {};
Object obj = constructor.newInstance(实际参数列表);//利用得到的构造器传递实参来创建对象
System.out.println(obj);
}catch(Exception e){
System.out.println(e.getMessage());
}
}
public static void c(){
try{
Class c1 = Class.forName("fanshe.Person");
Class[] 形式参数列表 = {Integer.TYPE,String.class};//注意是类型
Constructor constructor = c1.getDeclaredConstructor(形式参数列表);//得到形式参数列表对应的构造器
Object[] 实际参数列表 = {36,"ahhahah"};
Object obj = constructor.newInstance(实际参数列表);//利用得到的构造器传递实参来创建对象
System.out.println(obj);
}catch(Exception e){
System.out.println(e.getMessage());
}
}
public static void main(String[] args) {
c();
}
}
5.获取属性(成员) DemoC.java
package fanshe;
import java.lang.reflect.Field;
//获取属性
public class DemoC{
public void a(){
try{
Class c1 = Class.forName("fanshe.Person");
//Field[] getDeclaredFields
Field[] fields1 = c1.getDeclaredFields();//拿到的是自身所定义的所有属性,不管公有私有;父类继承下来的拿不到
//Field[] getFields()
Field[] fields2 = c1.getFields();//拿到的是所有的公开属性,包含继承下来的,不包含私有的属性
for (Field field:fields1) {
System.out.println(field.getName());
}
System.out.println("--------------------------");
for (Field field: fields2) {
System.out.println(field.getName());
}
}catch(Exception e){
System.out.println(e.getMessage());
}
}
public void b(){
try{
Class c1 = Class.forName("fanshe.Person");
//getDeclaredField是可以获取一个类本身的所有字段.
//Field getField(String name)
Field field1 = c1.getDeclaredField("id");
//忽略访问权限修饰符的安全检查
d.setAccessible(true);//暴力反射
Object value2 = d.get(p);
System.out.println(value2);
//即在a方法中得出的那四个中查找
//getField只能获取类及其父类的public 字段.
//Field getField(String name)
Field field2 = c1.getField("fname");//即在上面得出的那三个中查找
Field:成员变量
操作:
1.设置值: set(Object obj,Object value)
2.获取值:get(Object obj)
Person p = new Person();
//获取p对象的值
Object result = field2.get(p);
//设置p对象的值
field2.set(p,"张三);
System.out.println(field1);
System.out.println(field2);
}catch(Exception e){
System.out.println(e.getMessage());
}
}
public static void main(String[] args) {
new DemoC().b();
}
}
6.获取方法 DemoD.java
package fanshe;
import sun.util.cldr.CLDRLocaleDataMetaInfo;
import java.lang.reflect.Method;
//获取方法
public class DemoD {
public static void a(){
try{
Class c1 = Class.forName("fanshe.Person");
Method[] methods1 = c1.getDeclaredMethods();//获取自己声明的方法,无论公有还是私有
Method[] methods2 = c1.getMethods();//获取自己的方法和从父类继承的公有方法
for (Method method:methods1) {
System.out.println(method.getName());
}
System.out.println("------------");
for (Method method:methods2) {
System.out.println(method.getName());
}
}catch(Exception e){
System.out.println(e.getMessage());
}
}
public static void b(){
try{
Class c1 = Class.forName("fanshe.Person");
Class[] 形式参数列表 = {};
//从自己定义的方法中查找名字叫eat,形参列表为形式参数列表的方法
Method method = c1.getDeclaredMethod("sleep", int.class, String.class);
//从自己和父类中查找a方法,形式参数列表为形式参数列表的公有方法
Method method2 = c1.getMethod("c",形式参数列表);
System.out.println(method);
System.out.println(method2);
}catch(Exception e){
System.out.println(e.getMessage());
}
}
//方法的调用
public static void c(){//调用公有方法
try{
Class c1 = Class.forName("fanshe.Person");
Method method = c1.getDeclaredMethod("eat");
Object obj = c1.newInstance();
/*
invoke方法的参数,一个是Object类型,也就是调用该方法的对象,
第二个参数是一个可变参数类型
到Method.invoke()实际上并不是自己实现的反射调用逻辑,而是委托给sun.reflect.MethodAccessor来处理。
每个实际的Java方法只有一个对应的Method对象作为root,。
这个root是不会暴露给用户的,而是每次在通过反射获取Method对象时新创建Method对象把root包装起来再给用户。
在第一次调用一个实际Java方法对应得Method对象的invoke()方法之前,实现调用逻辑的MethodAccessor对象还没创建;
等第一次调用时才新创建MethodAccessor并更新给root,然后调用MethodAccessor.invoke()真正完成反射调用。
Object invoke(Object obj,...)
*/
Object result = method.invoke(obj);
//obj对象执行eat方法,参数为实参列表 此实参列表为空
//获取方法名称:method.getName()
}catch(Exception e){
System.out.println(e.getMessage());
}
}
public static void d(){//调用私有方法
try{
Class c1 = Class.forName("fanshe.Person");
Method method = c1.getDeclaredMethod("sleep", int.class, String.class);
Object obj = c1.newInstance();
method.setAccessible(true);//反射 强行的进行调用,设置其为可以访问的
method.invoke(obj,3,"中国");//obj - 从中调用底层方法的对象(简单的说就是调用谁的方法用谁的对象)args - 用于方法调用的参数
}catch(Exception e){
System.out.println(e.getMessage());
}
}
public static void main(String[] args) {
d();
}
}
7.DemoE.java 多个参数省略的写法
package fanshe;
import java.util.Arrays;
public class DemoE {
public void a(String a){
System.out.println(a);
}
public void b(String[] a){
System.out.println(a);
}
public void c(String...a){//同b方法 不确定几个参数
System.out.println(Arrays.toString(a));
}
public static void main(String[] args) {
DemoE de = new DemoE();
de.c("a","b");
}
}
8.万能sql写法
package dao;
import bean.StuInfo;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class BaseDAO {
public String save(Object obj){
Class c = obj.getClass();//获取类的对象
String className = c.getSimpleName();//获取类名
String ppppp = "";
String vvvvv = "";
String sql = "insert into "+className+"(PPPPP) values(VVVVV)";
try{
Field[] fields = c.getDeclaredFields();
for (Field field:fields) {
String fieldName = field.getName();//userId
String methodName = "get"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);//getUserId
Method method = c.getDeclaredMethod(methodName);
Object value = method.invoke(obj);
ppppp+=fieldName+",";
vvvvv+="'"+value+"',";
}
ppppp = ppppp.substring(0,ppppp.length()-1);
vvvvv = vvvvv.substring(0,vvvvv.length()-1);
sql = sql.replace("PPPPP",ppppp);
sql = sql.replace("VVVVV",vvvvv);
}catch(Exception e){
System.out.println(e.getMessage());
}
return sql;
}
public static void main(String[] args){
BaseDAO base = new BaseDAO();
/*UserInfo ui = new UserInfo(1,"张三",23,"男","宝鸡","123",1);
String sql = base.save(ui);
System.out.println(sql);*/
StuInfo si = new StuInfo(1,"awe","33");
String sql = base.save(si);
System.out.println(sql);
}
}
9.在不能改变该类的任意代码下,可以创建任意类的对象,可以执行任意方法
package reflect;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
/*
框架类
*/
public class ReflectTest {
public static void main(String[] args) throws Exception{
//要求:在不能改变该类的任意代码下,可以创建任意类的对象,可以执行任意方法
/*
实现:1.配置文件 2.反射
步骤:
1.将需要创建的对象的全类名和需要执行的方法定义在配置文件中
2.在程序中加载读取配置文件
3.使用反射技术加载类文件进内存
4.创建对象
5.执行方法
*/
//1.加载配置文件
//1.1创建Properties对象
Properties pro = new Properties();
//1.2加载配置文件,转换为一个集合
//1.2.1获取class目录下的配置文件
ClassLoader classLoader = ReflectTest.class.getClassLoader();//获取类加载器
InputStream inputStream =classLoader.getResourceAsStream("pro.properties");//获取这个资源对应的字节流
pro.load(inputStream);//装载字节流文件
//2.获取配置文件中定义的数据
String className = pro.getProperty("className");//获取到全类名
String methodName = pro.getProperty("methodName");//获取方法名
//3.加载该类进内存
Class cls = Class.forName(className);
//4.创建对象
Object obj = cls.newInstance();
//5.获取方法对象
Method method = cls.getMethod(methodName);
//6.执行方法
method.invoke(obj);
}
}
pro.properties
className = reflect.Student //全类名
methodName = sleep
10.赋录
Person.java
package fanshe;
public class Person extends Parent{
private Integer id;
public String name;
public Integer age;
private String minzu;
public Person(){
System.out.println("我是无参数Person构造器!");
}
public Person(int id){
this.id = id;
System.out.println("我是Person类的有一个Int参数的构造器!");
}
public Person(int id,String name){
this.id = id;
this.name = name;
System.out.println("我是Person类的有两个参数Int和String的构造器!");
}
public void eat(){
System.out.println("人都具有吃饭的方法");
}
private void sleep(int a,String b){
System.out.println("人都具有睡觉的方法"+a+"\t"+b);
}
}
Parent.java
package fanshe;
public class Parent {
private Integer fid;
public String fname;
public void c(){
System.out.println("父类a方法");
}
private void d(){
System.out.println("父类b方法");
}
}
Student.java
package reflect;
public class Student {
public void sleep(){
System.out.println(".....sleep");
}
}