反射-----框架设计的灵魂

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");
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值