反射机制

目录


反射机制

【拓展1】以流的形式直接返回

【拓展2】 获取一个文件的绝对路径

     1.通用方式:

    2.直接以流的形式返回:

【拓展3】可变长度参数

1、 反射机制有何用?

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

3、反射机制的相关重要类有哪些?

4、要操作一个类的字节码,需要首先获取到这个类的字节码,怎么获取java.lang.Class实例?

5、 获取到Class,能干什么?

6、 验证反射机制的灵活性?

7、 Class.forName()发生了什么?

8、 资源绑定器

9、 获取Field

10、 通过反射机制,反编译一个类的属性Field

11、  怎么通过反射机制访问一个java对象的属性?

12、  反射Method

13、  反编译一个类的方法

14、  通过反射机制怎么调用一个对象的方法?

15、  反射Constructor

16、 通过反射机制调用构造方法实例化java对象?(即通过反射机制怎么new对象?)

17、  给你一个类,怎么获取这个类的父类?已经实现了那些接口?


反射机制

【拓展1】以流的形式直接返回

 public class IoPropertiesTest {
     public static void main(String[] args) throws Exception {
         //获取一个文件的绝对路径
       /*  String path = Thread.currentThread().getContextClassLoader().getResource("classinfo2.properties").getPath();
         FileReader reader = new FileReader(path);*/
 ​
         InputStream reader = Thread.currentThread().getContextClassLoader().getResourceAsStream("classinfo2.properties");
 ​
         Properties pro = new Properties();
         pro.load(reader);
         reader.close();
 ​
         //通过key获取value
         String className = pro.getProperty("className");
         System.out.println(className);
     }
 }

 

【拓展2】 获取一个文件的绝对路径

     1.通用方式:

不会受到环境移植的影响但改文件要求放在类路径下:String path = Thread.currentThread.getContextClassLoader().getResource("写相对路径,但是这个相对路径从src出发开始找").getPath();

如:

  • String path = Thread.currentThread.getContextClassLoader().getResource("写相对路径,abc").getPath();//必须保证src下有abc文件。

  • String path = Thread.currentThread.getContextClassLoader().getResource("写相对路径,a/b/c").getPath();//必须保证src下有a目录,a目录下有b目录,b目录下有c文件。

 public class IoPropertiesTest {
     public static void main(String[] args) throws Exception {
         //获取一个文件的绝对路径
       /*  String path = Thread.currentThread().getContextClassLoader().getResource("classinfo2.properties").getPath();
         FileReader reader = new FileReader(path);*/
 ​
         InputStream reader = Thread.currentThread().getContextClassLoader().getResourceAsStream("classinfo2.properties");
 ​
         Properties pro = new Properties();
         pro.load(reader);
         reader.close();
 ​
         //通过key获取value
         String className = pro.getProperty("className");
         System.out.println(className);
     }
 }

    2.直接以流的形式返回:

InputStream in = Thread.currentThread.getContextClassLoader().getResourcceAsStream("com/cc/test.properties");

【拓展3】可变长度参数

int... args 这就是可变长度参数 语法是:类型... (注意:一定是三个点)

1.可变长度参数要求的参数个数是0~N个; 2.可变长度参数在参数列表中必须在最后一个位置上,且可变长度参数只能有一个 3.可变长度参数可以当做是一个数组来看待

public class ArgsTest {
     public static void main(String[] args) {
         m();
         m(111,222);
         m(111,222,333);
         //编译报错
 //        m("abc");
 ​
         String();
         String("aa","bb","cc");
         //传一个数组
         String[] strs ={"我","爱","中","国"};
         String(strs);
         //直接传一个数组
         String(new String[]{"我","爱","中","国"});
 ​
         intString(1,"aaa");
 ​
 ​
     }
 ​
     public static void m(int... args) {
         System.out.println("m可变长度参数执行了!");
     }
 ​
     public static void String(String... args) {
         System.out.println("String可变长度参数执行了");
         for (int i = 0; i <args.length;i++){
             System.out.println(args[i]);
         }
     }
 ​
     //必须在最后,且只能有一个
 /*    public static void intString(int... args,String... args1) {
 ​
     }*/
     public static void intString(int i,String... args) {
         System.out.println("intString可变长度参数执行了");
     }
 }

1、 反射机制有何用?

  • 通过java语言中的反射机制可以操作字节码文件。

  • 有点类似于黑客(可以读取和修改字节码文件)

  • 通过反射机制可以操作代码片段(class文件)

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

 java.lang.reflect.*

3、反射机制的相关重要类有哪些?

java.lang.Class:代表整个字节码,代表一个类型,代表整个类 java.lang.reflect.Method:代表字节码中的方法字节码,代表类中的方法 java.lang.reflect.Constructor:代表字节码中的构造方法,代表类中的构造方法 java.lang.reflect.Field:代表字节码中的属性字节码,代表类中的成员变量(静态变量+实例变量)

 //java.lang.Class
 public class User{
     //Field
     int no;
     
     //Constructor
     public User(){
         
     }
     public User(int no){
         this.no = no;
     }
     //Method
     public void setno(int no){
         this.no = no;
     }
     public int getno(int no){
         return no;
     }
 }

4、要操作一个类的字节码,需要首先获取到这个类的字节码,怎么获取java.lang.Class实例?

三种方式: 1、Class c = Class.forName("完整类名带包名"); 2、Class x = 对象.getClass(); 3、Class c = 任何类型.class();

 public class ReflectTest01 {
     /*
     要操作一个类的字节码,需要首先获取到这个类的字节码,怎么获取java.lang.Class实例?
     三种方式:
           1、Class c = Class.forName("完整类名带包名");
           2、Class x = 对象.getClass();
           3、Class c = 任何类型.class();
     */
     public static void main(String[] args){
 /*        Class.forName()
            1、静态方法
            2、方法的参数是一个字符串
            3、字符串需要的是一个完整的类名
            4、完整类名必须带有包名,java.lang也不能省略
 */
         Class c1 = null;
         Class c2 = null;
         try {
             //法一
             c1 = Class.forName("java.lang.String");
             c2 = Class.forName("java.util.Date");
             Class c3 = Class.forName("java.lang.Integer");
             Class c4 = Class.forName("java.lang.System");
         } catch (ClassNotFoundException e) {
             e.printStackTrace();
         }
 ​
         //法二
         //java 中任何一个对象都有一个方法:getClass()
         String s = "abc";
         Class x = s.getClass();//x代表String.class 字节码文件,x代表String类型
         System.out.println(c1 == x);//true( == 判断的是对象的内存地址。)
 ​
         Date time = new Date();
         Class y = time.getClass();
         System.out.println(c2 == y);//true(c2和y两个变量的内存地址都是一样的,都指向方法区中的字节码)
 ​
         //法三
         //java语言中任何一中类型,包括基本数据类型,它都有.class属性
         Class z = String.class;//z代表String类型
         Class l = Date.class;//l代表Date类型
         Class m = int.class;//m代表int类型
         Class e = double.class;//n代表double类型
     }
 }
 

输出结果:

true

true

5、 获取到Class,能干什么?

  • 通过Class的newInstance()方法来实例化对象 注意:newInstance()方法内部实际调用了无参构造方法,必须保证无参构造存在才可以!如果没有这个无参构造方法会出现实例化异常。

/*
 获取到Class,能干什么?
 通过Class的newInstance()方法来实例化对象
 注意:newInstance()方法内部实际调用了无参构造方法,必须保证无参构造存在才可以!
 */
 public class ReflectTest02 {
     public static void main(String[] args) {
         //这是不使用反射机制,创建对象
         User user = new User();//com.cc.java.bean.User@1b6d3586
         System.out.println(user);
 ​
         //下面是使用反射机制,创建对象
         try {
             //通过反射机制,获取Class,通过Class来实例化对象
             Class c = Class.forName("com.cc.java.bean.User");
 ​
             //newInstance()这个方法会调用User这个类的五参数构造方法,完成对象的创建
             //重点是:newInstance()调用的是无参构造,必须保证无参构造是存在的!
             Object obj = c.newInstance();
             System.out.println(obj);//com.cc.java.bean.User@4554617c
 ​
 ​
         } catch (ClassNotFoundException e) {
             e.printStackTrace();
         } catch (IllegalAccessException e) {
             e.printStackTrace();
         } catch (InstantiationException e) {
             e.printStackTrace();
         }
 ​
     }
 }

6、 验证反射机制的灵活性?

java代码写一遍,在不改变java源代码的基础之上,可以做到不同对象的实例化。

/*
 验证反射机制的灵活性?
     java代码写一遍,在不改变java源代码的基础之上,可以做到不同对象的实例化。
     非常之灵活(符合OCP开闭原则:对扩展开放,对修改关闭)
 ​
     后期需要学高级框架,包括:ssm ssh
     这些高级框架底层实现原理都采用了反射机制,所以反射机制是重要的
     学会了反射机制有利于理解剖析底层的源代码
 */
 public class ReflectTest03 {
     public static void main(String[] args) throws Exception {
 ​
         //这种方式代码就写死了,只能创建一个User类型的对象
         User user = new User();
         System.out.println(user);
 ​
         //以下代码是灵活的,代码不需要改动,可以修改配置文件,配置文件修改后,可以创建不同的实例化对象
         //通过IO流读取classinfo.properties文件
         FileReader reader = new FileReader("E:/ssm/annotationandreflect/classinfo.properties");
         //创建属性类对象
         Properties pro = new Properties();
         //加载
         pro.load(reader);
         //关闭流
         reader.close();
         //通过key获取value
         String className =  pro.getProperty("className");
         System.out.println(className);
 ​
         //通过反射机制创建实例化对象
         Class c = Class.forName(className);
         Object obj = c.newInstance();
         System.out.println(obj);
 ​
     }
 ​
 }
 

classinfo.properties(更改className值,可以直接影响到通过反射实例出的对象类型):

 #className=com.cc.java.bean.User
 className = java.util.Date

7、 Class.forName()发生了什么?

如果只希望一个类的静态代码块执行,其他代码一律不执行,可以使用: Class.forName("完整类名"); 此方法会导致类加载,静态代码块执行!

在这里,对该方法的返回值不感兴趣,主要是为了使用“类加载”这个动作。

 public class ReflectTest04 {
     /*
     研究一下:Class.forName()发生了什么?
     记住,重点:
     如果只希望一个类的静态代码块执行,其他代码一律不执行,可以使用:
         Class.forName("完整类名");
      此方法会导致类加载,静态代码块执行!
      */
     public static void main(String[] args) {
         try {
             Class.forName("com.cc.java.bean.MyClass");
         } catch (ClassNotFoundException e) {
             e.printStackTrace();
         }
     }
 }
 //静态代码块在类加载时执行,并且只执行一次
 public class MyClass {
     static {
         System.out.println("MyClass的静态代码快执行了!");
     }
 }

8、 资源绑定器

ResourceBundle resourceBundle = ResourceBundle.getBundle("classinfo2"); String className = resourceBundle.getString(key);

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

 

9、 获取Field

 public class ReflectTest05 {
     public static void main(String[] args) throws Exception{
         Class studentClass = Class.forName("com.cc.java.bean.Student");
         //获取类名
         String name =  studentClass.getName();
         String simpleName = studentClass.getSimpleName();
         System.out.println(name);
         System.out.println(simpleName);
         //获取类中所有Field
         Field[] field = studentClass.getFields();
         System.out.println("field的长度为:"+field.length);
         //取出这个Field
         Field f = field[0];
         //取出这个Field的名字
         String fname = f.getName();
         System.out.println("取出这个Field的名字:"+fname);
         //获取所有Field
         Field[] fs = studentClass.getDeclaredFields();
         System.out.println("所有field的长度为"+fs.length);
         System.out.println("=========================");
         //遍历
         for (Field field1:fs){
             //获取属性名
             System.out.println(field1.getName());
             //获取属性类型
             Class field1Type = field1.getType();
             String name1 = field1Type.getName();
             System.out.println("属性类型名:"+name);
             String simpleName1ame = field1Type.getSimpleName();
             System.out.println("属性类型简称:"+simpleName1ame);
             //获取属性修饰符(代号)
             int i = field1.getModifiers();
             System.out.println(i);
             //获取属性修饰符名称,将“代号”转换成“字符串”
             String modifierString = Modifier.toString(i);
             System.out.println(modifierString);
 ​
         }
         //取出这个Field的类型
 //        f.getType()
     }
 }

10、 通过反射机制,反编译一个类的属性Field

public class ReflectTest06 {
     public static void main(String[] args) throws Exception{
 //        创建这个是为了拼接字符
         StringBuilder s = new  StringBuilder();
 //        Class studentClass = Class.forName("com.cc.java.bean.Student");
 //        Class studentClass = Class.forName("java.lang.Integer");
 //        Class studentClass = Class.forName("java.lang.Stringr");
         Class studentClass = Class.forName("java.util.Date");
         s.append( Modifier.toString(studentClass.getModifiers()) +" class "+ studentClass.getSimpleName()+"{"+"\n");
 ​
         Field[] fields = studentClass.getDeclaredFields();
         for (Field field:fields){
             s.append("\t");
             s.append(Modifier.toString(field.getModifiers()));
             s.append(" ");
             s.append(field.getType().getSimpleName());
             s.append(" ");
             s.append(field.getName());
             s.append(";\n");
         }
 ​
         s.append("}");
         System.out.println(s);
     }
 }

11、  怎么通过反射机制访问一个java对象的属性?

  • 给对象赋值set

  • 获取属性的值get

 public class ReflectTest07 {
     public static void main(String[] args) throws Exception{
         //不使用反射机制的话,怎么去访问一个对象的属性呢?
         Student s = new Student();
         //给属性赋值
         s.name = "张三";//三要素:给s对象的no属性赋值“张三”
                               //要素1:对象
                               //要素2:name属性
                               //要素3:“张三”
          // 读属性值
         System.out.println(s.name);
 ​
 ​
 ​
 ​
 ​
         
         //使用反射机制,怎么去访问一个对象的属性?  (set get)
         Class c = Class.forName("com.cc.java.bean.Student");
         Object obj = c.newInstance(); //obj就是Student对象,(底层调用无参构造方法)
         //获取name属性(根据属性名称来获取Field)
         Field nameFiled = c.getDeclaredField("name");
         //给obj对象(Student对象)的no属性赋值
         /*
         虽然使用了反射机制,但三要素还是缺一不可
                               //要素1:obj对象
                               //要素2:name属性
                               //要素3:“李四”
          */
         nameFiled.set(obj,"李四");
         // 读属性值
         //两个要素:获取obj对象的name属性的值
         System.out.println(nameFiled.get(obj));
 ​
         //可以访问私有属性吗?
         Field noField = c.getDeclaredField("no");
         //打破封装(反射机制的缺点:打破封装,可能会给不法分子留下机会!!!)
         noField.setAccessible(true);
         //给no属性赋值
         noField.set(obj,123);
         //获得no属性的值
         System.out.println(noField.get(obj));
 ​
 ​
         Field maxField = c.getDeclaredField("max");
         maxField.setAccessible(true);
         maxField.set(obj,5);
         System.out.println(maxField.get(obj));
 ​
     }
 }
 ​

12、  反射Method

 public class ArgsTest {
     public static void main(String[] args) {
         m();
         m(111,222);
         m(111,222,333);
         //编译报错
 //        m("abc");
 ​
         String();
         String("aa","bb","cc");
         //传一个数组
         String[] strs ={"我","爱","中","国"};
         String(strs);
         //直接传一个数组
         String(new String[]{"我","爱","中","国"});
 ​
         intString(1,"aaa");
 ​
 ​
     }
 ​
     public static void m(int... args) {
         System.out.println("m可变长度参数执行了!");
     }
 ​
     public static void String(String... args) {
         System.out.println("String可变长度参数执行了");
         for (int i = 0; i <args.length;i++){
             System.out.println(args[i]);
         }
     }
 ​
     //必须在最后,且只能有一个
 /*    public static void intString(int... args,String... args1) {
 ​
     }*/
     public static void intString(int i,String... args) {
         System.out.println("intString可变长度参数执行了");
     }
 }

 

13、  反编译一个类的方法

public class ReflectTest09 {
     public static void main(String[] args) throws Exception{
         Class c = Class.forName("com.cc.java.service.UserService");
         StringBuilder s = new StringBuilder();
         s.append(Modifier.toString(c.getModifiers()) +" class "+ c.getSimpleName()+"{"+"\n");
         Method[] methods = c.getDeclaredMethods();
         for (Method method : methods){
 ​
             s.append(Modifier.toString(c.getModifiers()));
             s.append(" ");
             s.append(method.getReturnType().getSimpleName());
             s.append(" ");
             s.append(method.getName());
             s.append("(");
             //参数列表
             Class[] parameterTypes = method.getParameterTypes();
             for (Class parameterType:parameterTypes){
                 s.append(parameterType.getSimpleName());
                 s.append(",");
             }
             //删除指定下标位置上的字符
             s.deleteCharAt(s.length()-1);
             s.append("){"+"\n");
             s.append("}"+"\n");
 ​
         }
         s.append("\n");
         s.append("}");
 ​
         System.out.println(s);
     }
 }

14、  通过反射机制怎么调用一个对象的方法?

 public class ReflectTest10 {
     public static void main(String[] args) throws Exception{
         //不使用用反射机制,怎么调用方法?
         //创建对象
         UserService userService = new UserService();
         //调用方法
         boolean loginSuccess = userService.login("admin","123");
         System.out.println(loginSuccess);
 ​
 ​
         //使用用反射机制,怎么调用方法?
         /*
         四要素:
         1、对象userService
         2、login方法名
         3、实参列表
         4、返回值
          */
         Class userServicef = Class.forName("com.cc.java.service.UserService");
         Object o = userServicef.newInstance();
         Method method = userServicef.getDeclaredMethod("login",String.class,String.class);
 //        returnValue返回值
         Object returnValue = method.invoke(o, "admin", "123");
         System.out.println(returnValue);
 ​
 ​
     }
 ​
 }

15、  反射Constructor

 public class ReflectTest11 {
     public static void main(String[] args) throws Exception{
         StringBuilder s = new StringBuilder();
 //        Class vipClass = Class.forName("com.cc.java.bean.Vip");
         Class vipClass = Class.forName("java.util.Date");
         Object obj = vipClass.newInstance();
 ​
         s.append(Modifier.toString(vipClass.getModifiers()) + " class " + vipClass.getSimpleName() + "{"+"\n");
 ​
         Field[] fields = vipClass.getDeclaredFields();
         for (Field field : fields){
             s.append(Modifier.toString(field.getModifiers()) + " ");
             s.append(field.getType().getSimpleName() + " ");
             s.append(field.getName());
             s.append(";" + "\n");
         }
 ​
 ​
         //拼接构造方法
         Constructor[] constructors = vipClass.getDeclaredConstructors();
         for (Constructor constructor:constructors){
 /*            s.append(Modifier.toString(constructor.getModifiers()) + " " +constructor.getName() + "()");
             s.append("{}" + "\n");*/
             s.append(Modifier.toString(constructor.getModifiers()) + " " + vipClass.getSimpleName());
             s.append("(");
 ​
             //拼接参数
             Class[] parameterTypes = constructor.getParameterTypes();
             for (Class parameterType : parameterTypes){
                 s.append(parameterType.getSimpleName() + ",");
             }
             s.deleteCharAt(s.length()-1);
             s.append(")");
             s.append("{"+"\n");
             s.append("}" + "\n");
         }
         s.append("}");
         System.out.println(s);
     }
 ​
 }

16、 通过反射机制调用构造方法实例化java对象?(即通过反射机制怎么new对象?)

public class ReflectTest12 {
     public static void main(String[] args) throws Exception{
 ​
         //不使用反射机制怎么new对象?
         Vip vip1 = new Vip();
         Vip vip2 = new Vip(110,"张三","2000-1-20", true);
         //使用反射机制怎么new对象?
         Class c = Class.forName("com.cc.java.bean.Vip");
         //调用无参构造方法
         Object obj = c.newInstance();
         System.out.println(obj);
         //调用有参构造方法
         //1、先获取到这个有参构造方法
         Constructor constructor = c.getDeclaredConstructor(int.class, String.class, String.class, boolean.class);
         //2、调用构造方法new对象
         Object ob = constructor.newInstance(110, "李四", "1990 - 10 - 11", true);
         System.out.println(ob);
 ​
         //3、调用无参构造
         Constructor constructor1 = c.getDeclaredConstructor();
         Object ob1 = constructor1.newInstance();
         System.out.println(ob1);
     }
 }

17、  给你一个类,怎么获取这个类的父类?已经实现了那些接口?

 public class ReflectTest13 {
     public static void main(String[] args) throws Exception{
         //String举例
         Class stringClass = Class.forName("java.lang.String");
 ​
         //获取Spring父类
         Object object = stringClass.newInstance();
         Class superClasses = stringClass.getSuperclass();
         System.out.println(superClasses.getName());
 ​
         //获取Spring类实现的所有接口(一个类可以实现多个接口
         Class[] interfaces = stringClass.getInterfaces();
         for (Class in:interfaces){
             System.out.println(in.getName());
         }
     }
 }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值