Java笔记13——反射

概论

  1. 反射机制有什么用?

    通过java语言中的反射机制可以操作(读和修改)字节码文件

    通过反射机制可以操作代码片段

  2. 反射机制的相关类在哪个包下?

    java.lang.reflect.*

  3. 反射机制相关的类有哪些?

    java.lang.class:代表字节码文件,代表一个类型

    java.lang.reflecr.method:代表字节码中的方法字节码

    java.lang.reflect.Constructor:代表字节码中的构造方法字节码

    java.lang.reflect.Field:代表字节码中的属性字节码

获取Class的三种方式

/*
要操作一个类的字节码,要首先获取这个类的字节码
怎么获取java.lang.Class实例?
     三种方式:
          第一种:Class c =new Class("完整路径带包名");
          第二种:Class c =对象.getClass();
          第三种:Class c int.class;
 */
public class ReflectTest01 {
    public static void main(String[] args) throws ClassNotFoundException {
        /*
        Class.forName()
             1.静态方法
             2.方法的参数是一个字符串
             3.字符串需要的是一个完整的类名
             4.完整类名必须带有包名,
         */
        Class c1 =Class.forName("java.lang.String");
        Class c2 =Class.forName("java.util.Date");
        
        //java中任何一个对象都有一个方法,getClass()
        String s="sada";
        Class x =s.getClass();    //x代表String类型

        //第三种方法:java语言中任何一种类型,哪怕是基本数据类型,他都有.calss属性
        Class z=String.class;  //z代表String类型

    }
}

获取到Class能做什么?

newInstance方法内部实际上调用了无参数构造方法,必须保证无参数构造存在才行

/*
获取到Class,能干什么?
       通过Class的newInstance()方法来实例化对象
       注意:newInstance方法内部实际上调用了无参数构造方法,必须保证无参数构造存在才行
 */
public class ReflectTest02 {
    public static void main(String[] args) {
        //通过反射机制获取User的Class
        try {
           Class c= Class.forName("com.baidu.bean.User.java");
            //newInstance()  创建的是一个User的实例,调用了User的无参构造方法
            //必须保证User的无参构造函数是存在的
           Object obj=  c.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
}

研究一下:Class.forName()发生了什么?

如果你只是希望一个类的静态代码块执行,其他代码一律不执行,你可以使用:

Class.forName(“完整类名”);

这个方法的执行会导致类加载,类加载时,静态代码块执行

提示:

后面JDBC技术会使用到

获取文件的绝对路径

/*
研究一下文件路径的问题
    怎样获取一个文件的绝对路径.以下这种讲解方式是通用的.但前提是:文件需要在类路径下,才能使用这种方式
 */
public class AboutPathTest01 {
    public static void main(String[] args) throws FileNotFoundException {
        //这种方式的路径的缺点是:移植性差,IDEA中默认的当前路径就是1.txt的根
        //这个代码假设离开了IDEA,换到了其他位置,可能当前路径就不行了
//        FileReader fr=new FileReader("User.java" );

        //接下来说一种比较通用的方式,即使代码位置更换了,这样编写仍然是通用的
        //注意:前提是这个文件必须在类路径下
        //什么事类路径下?  凡是在src下的都是类路径下
        //src是类的根路径
        /*
        解释一下:
             Thread.CurrentThread()  当前线程方法
             getContextClassLoader()   是线程对象方法,可以获取到当前线程的类加载器对象
             getResource()    [获取资源]是类加载器对象的方法,当前线程的类加载器默认从类的根路径下加载资源.
         */

//        String path =Thread.currentThread().getContextClassLoader()
//                .getResource("从类的根路径下作为起点开始").getPath();
//        //以上代码可以拿到文件的绝对路径
//        System.out.println(path);

        //获取db.properties文件的绝对路径
        String path2 =Thread.currentThread().getContextClassLoader()
                .getResource("com/baidu/reflect/db.properties").getPath();
        System.out.println(path2);

    }

}

String path =Thread.currentThread().getContextClassLoader()
.getResource(“从类的根路径下作为起点开始”).getPath();

这种方式是为了获取一个文件的绝对路径,但是该文件要求放在类路径下,换句话说:也就是放到src下面.

src是类的根路径

这是通用的方式的,不受环境移植的影响

IO中的用途

直接以流的形式返回

InputStream reader =Thread.currentThread().getContextClassLoader().getResourceStream( “name”);

资源绑定器

/*
java.util包下提供了一个资源绑定器,便于获取配置文件的内容
使用以下方式的时候,属性配置文件xxx.properties必须放到类路径下
 */
public class ResoureBundle {
    public static void main(String[] args) {
        //资源绑定器,只能绑定xxx.properties文件,并且这个文件必须在类路径下.文件拓展名也必须是properties
        //并且在写文件的时候,路径后面的拓展名不用写
        ResourceBundle bundle =ResourceBundle.getBundle("com/baidu/reflect/db");
        String className =bundle.getString("className");
        System.out.println(className);


    }
}

双亲委派机制(了解)

java中为了保证类的加载的安全,使用了双亲委派机制,优先从启动类加载器中加载,这个称为"父"

“父"无法加载到,再从拓展类加载器中加载,这个称为"母”

双亲委派,如果都加载不到,才会考虑从应用类加载器中加载,直到加载到为止

获取Field(了解)

public static void main(String[] args) throws ClassNotFoundException {
    //获取整个类
    Class studentClass = Class.forName("com.baidu.bean.Student");
    //获取所有的类Filed
   Field[] fields= studentClass.getFields();
    System.out.println(fields.length);  //测试数组中只有一个元素
    //取出这个Filed的名字
    String fieldName =fields[0].getName();
    System.out.println(fieldName);
    System.out.println("=========================");

    //获取所有的Field
    Field[] fs = studentClass.getDeclaredFields();
    System.out.println(fs.length); //4
    for (Field f : fs) {
        //获取属性的修饰符列表
        int i =f.getModifiers(); //返回的修饰符是一个数字,每个数字是修饰符的代号
        System.out.println(i);
        //可以将这个"代号"数字转换成字符串吗?
        String moddifierString = Modifier.toString(i);
        System.out.println(moddifierString);
        //获取属性的类型
        Class fieldType = f.getType();
        String fName =fieldType.getName();
        System.out.println(fName);
        //获取属性的名字
        System.out.println(f.getName());
    }
}
## 反射机制访问对象属性(重点)

核心代码:

/*
怎样通过反射机制访问一个java对象的属性?
           给属性赋值set
           获取属性的值get
 */
public class ReflectTest04 {
    public static void main(String[] args) throws Exception {
        Class studentClass =Class.forName("com.baidu.bean.Student");
        //获取它的属性
        Object obj =studentClass.newInstance();//obj就是Student的对象(底层调用无参数构造方法)
        //获取id属性(依靠名字区分)
        Field noField =studentClass.getDeclaredField("id");
        //给obj对象(Student对象)的no属性赋值
        /*
        虽然使用了反射机制,但是三要素依旧缺一不可
             要素1:obj对象
             要素2:no属性
             要素3:1234值
         */
        noField.set(obj,1234); //给obj对象的no属性赋值1234
        //读取属性的值
        System.out.println(noField.get(obj));
        //可以访问私有属性吗?
        Field nameField = studentClass.getDeclaredField("name");
        //打破封装(反射机制的缺点,打破封装,可能会给不法分子留下机会)
        //这样设置完后,在外部也是可以访问到private的
        nameField.setAccessible(true);
        //给name属性赋值
        nameField.set(obj,"jike");
        System.out.println(nameField.get(obj));


    }
}

通过反射机制调用方法(重点)

核心代码:

Object retValue= loginMethod. invoke(obj,“admin”,“123”);
//翻译一下:调用obj对象中的loginMethod的方法,返回值是retValue,invoke负责调用

/*
通过反射机制怎样调用一个对象的方法
 */
public class ReflectTest07 {
    public static void main(String[] args)  throws Exception{
        Class userService =Class.forName("com.baidu.reflect.UserService");
        //创建对象
        Object obj= userService.newInstance();
        //获取Method
        Method loginMethod =userService.getDeclaredMethod("login", String.class, String.class);
        //调用方法
        /*
        要素分析:
             要素1:对象userService       obj是对象
             要素2:login方法名           "admin""123"是实参
             要素3:实参列表               retValue是返回值
             要素4:返回值
         */
        Object retValue= loginMethod. invoke(obj,"admin","123");
        //翻译一下:调用obj对象中的loginMethod的方法,返回值是retValue,invoke负责调用
        System.out.println(retValue);
    }
}

通过反射机制读取注解

public static void main(String[] args) throws ClassNotFoundException {
    Class c =Class.forName("com.baidu.annotation.AnnotationTest01");
    //判断类上面是否有这个注解
    if(c.isAnnotationPresent(MyAnnotationTest01.class)){
        //获取该注解对象
        MyAnnotationTest01 myAnnotation=(MyAnnotationTest01) c.getAnnotation(AnnotationTest02.class);
        //获取注解对象属性怎么办?和调接口没区别
        String value= myAnnotation.value();
        System.out.println(value);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值