java程序员从笨鸟到菜鸟之(四十五)反射初涉
2017-12-14 18:25
477 查看
反射概念
粗---先会使用
1 什么是java语言反射机制?
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
反射就是通过获取到该类的字节码文件对象---->即:Class类对象,通过Class类对象获取该类里面的一些属性(成员变量)、构造方法、成员方法等----如何获取等
说明:两种理解方式均可
2 面试题:如何获取类的字节码文件对象?并且有几种方式呢?
1)Object类中的getClass()方法,表示正在运行的Class类型的实例
2)数据类型的class属性 举例:String.class、Student.class
3)Class类中的特有方法:forName(String className)---(重点,数据库加载驱动:Drivers)---静态方法获得类名对应的Class对象
说明:开发中常使用的方式,因为第三种里面的参数是一个字符串;一个Class对象表示特定类的对象(属性)
注意:第三种方式的是类的全路径名称的字符串形式
实例1
说明1:出现黄色警告线原因---Class类实际是一个泛型类,大多数情况可以忽略类型参数,而使用原始的Class类;
说明2:三种方式都是Person类的字节码文件,所以三者通过"=="判断都是true;
注意:一个Class对象实际是一个类型,而此类型未必是一个类;int不是类,但int.class是一个Class类型的对象
回顾:在反射之前,在启动程序时,包含main方法的类首先被加载,它会加载所有需要的类,被加载的类又会继续加载它需要的类,以此类推;对于大型应用程序来说,会消耗很多时间,用户不耐烦。
反射应用:给用户一个启动速度比较快的幻觉---首先保证包含main方法的类没有显示地引用其它的类,在显示一个启动画面,然后通过调用Class.forName手工地加载其它的类
理解:虚拟机为每个类型管理一个Class对象;注意:不是每个对象,通过"=="运算符的比较也可以看出。
那么如何访问这些信息?通过专门的java类访问这些信息,保存这些信息的类被称为Class。
常用获取构造器的方法
(1)getName---返回类的全限定类名----补充的
(2)public Constructor<?>[] getConstructors()---返回的是一个公共构造方法所在数组
(3)public Constructor<?>[] getDeclaredConstructors():获取的是当前字节码文件对象中所有的(静态的,私有的,受保护的)构造方法数组
(4)public Constructor<T> getConstructor(Class<?>... parameterTypes):它反映此 Class 对象所表示的类的指定公共构造方法
参数说明:参数为对应构造方法的数据类型的字节码文件对象,形如String.class或int.class;可变参数类型
(5)public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):表示获取类或者接口中的指定的构造方法
实例2
(6)public 类名 newInstance():
说明:可以直接通过Class的newInstance()的方法,特点:对没有参数的默认构造器初始化并创建对象
除了Class的此方法,还有没有其它的途径创建对象?当然有
(1)public T newInstance(Object... initargs):
说明:传递的是实际参数(可变参数),该方法等效于创建一个类的对象(动态)
实例3 创建对象动态和静态(公共的构造方法)
注意:(2)和(3)以及(4)的newInstance()方法的返回值
那么问题来了,私有的构造方法能否创建对象?
(2)public void setAccessible(boolean flag):在访问的时候取消java语言访问检查(强制性)---常常是私有的构造方法;常常"fla
dcee
g=true" ----在给构造创建实例对象之前就应该取消检查
实例4
通过反射获取成员变量并使用:成员变量--->Field
(1)获取所有的公共的成员变量public Field[] getFields()
说明:所有的公共的可访问的字段,返回的是Field对象数组
(2)public Field[] getDeclaredFields()
说明:获取当前字节码文件对象中所有的公共的或者私有的字段
(3)public Field getField(String name)
说明:获取公共的指定的字段,参数为当前成员变量名称的字符串形式
(4)public Field getDeclaredField(String name)
说明:获取类或接口中已经声明的指定的字段(一般私有的)
注意1:如果给当前obj实例对象设置一个参数,将指定对象变量上此 Field对象表示的字段设置为指定的新值;
public void set(Object obj, Object value)----给obj实例对象里面的成员变量设置一个实际参数;obj为动态的对象(forName创建的形式)
注意2:如果想对私有成员变量设置值,必须在设置值之前取消Java语言的访问检查:Field类的方法---setAccessible(true);
注意3:输出每个对象不是地址的原因:多态
实例5
调用对象的成员方法----Class类的方法
(1) public Method[] getDeclaredMethods():
说明:得到此类对象本身的所有方法(公共,受保护、默认、私有),但不包括继承其它的方法(不管什么方式)
(2) public Method[] getMethods():获取当前该字节码文件对象(Person.class)中自己本身以及它父类中所有的公共成员方法(包括继承)
说明:除了自身的公共方法以外,还有继承的公共方法
(3) public Method getMethod(String name,Class<?>... parameterTypes):指定公共成员方法
参数1:表示方法名的字符串形式
参数2:该方法的参数类型的Class对象(数据类型的class属性) String.class(非实参)
说明:返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法(无继承的方法,自身类中特有的公共方法)。
(4) public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
说明:得到该对象(无继承方法)反映此 Class 对象所表示的类或接口的指定已声明方法(可以私有化)
参数1:表示当前针对哪个以实例对象进行方法的调用----疑问静态方法不需要obj吧!!!
参数2:当前调用该方法的时候里面传递的实际参数
说明:唯一有参数的,参数需要指明调用的动态对象,然后传递参数才能调用此对象的方法。
注意:如果是私有的方法,必须取消Java语言的访问检查---主要针对私有的方法---setAccessible(true)
实例6 通过反射获取成员变量并使用,之前使用对象调用成员方法
package demo;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Demo6 {
/**
* 需求:
* 通过反射获取成员变量并使用,之前使用对象调用成员方法
* 类似:
* Person p = new Person() ;
* p.show() ;
*/
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
Class<?> person = Class.forName("demo.Person");
Constructor<?> con = person.getConstructor();
Object instance = con.newInstance();//动态的创建了一个对象
Method[] met = person.getMethods();
Method me = person.getMethod("method1");
Object inv = me.invoke(instance);
System.out.println(inv);
}
}
反射的应用
reflect_handler的应用---体会
动态代理:
我给你ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?
属性集合类----动态代理的形式
粗---先会使用
1 什么是java语言反射机制?
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
反射就是通过获取到该类的字节码文件对象---->即:Class类对象,通过Class类对象获取该类里面的一些属性(成员变量)、构造方法、成员方法等----如何获取等
说明:两种理解方式均可
2 面试题:如何获取类的字节码文件对象?并且有几种方式呢?
1)Object类中的getClass()方法,表示正在运行的Class类型的实例
2)数据类型的class属性 举例:String.class、Student.class
3)Class类中的特有方法:forName(String className)---(重点,数据库加载驱动:Drivers)---静态方法获得类名对应的Class对象
说明:开发中常使用的方式,因为第三种里面的参数是一个字符串;一个Class对象表示特定类的对象(属性)
注意:第三种方式的是类的全路径名称的字符串形式
实例1
package demo; public class Demo1 { public static void main(String[] args) throws ClassNotFoundException { Person person=new Person(); Class<Person> person1=Person.class;//得到Person.class字节码文件对象 Class person2=person.getClass(); Class<?> person3 = Class.forName("demo.Person");//加载并且获得Person.class字节码文件对象 //如何方式3找不到类的全限定名:出现java.lang.ClassNotFoundException异常 } }
说明1:出现黄色警告线原因---Class类实际是一个泛型类,大多数情况可以忽略类型参数,而使用原始的Class类;
说明2:三种方式都是Person类的字节码文件,所以三者通过"=="判断都是true;
注意:一个Class对象实际是一个类型,而此类型未必是一个类;int不是类,但int.class是一个Class类型的对象
回顾:在反射之前,在启动程序时,包含main方法的类首先被加载,它会加载所有需要的类,被加载的类又会继续加载它需要的类,以此类推;对于大型应用程序来说,会消耗很多时间,用户不耐烦。
反射应用:给用户一个启动速度比较快的幻觉---首先保证包含main方法的类没有显示地引用其它的类,在显示一个启动画面,然后通过调用Class.forName手工地加载其它的类
Class类
在程序运行期间(前提),Java运行时系统始终为所有的对象维护着一个被称为运行时的标识类型,这个信息(标识类型的信息)跟踪着每个对象所属的类;虚拟机利用运行时类型信息选择相应的方法执行。理解:虚拟机为每个类型管理一个Class对象;注意:不是每个对象,通过"=="运算符的比较也可以看出。
那么如何访问这些信息?通过专门的java类访问这些信息,保存这些信息的类被称为Class。
常用获取构造器的方法
(1)getName---返回类的全限定类名----补充的
(2)public Constructor<?>[] getConstructors()---返回的是一个公共构造方法所在数组
(3)public Constructor<?>[] getDeclaredConstructors():获取的是当前字节码文件对象中所有的(静态的,私有的,受保护的)构造方法数组
(4)public Constructor<T> getConstructor(Class<?>... parameterTypes):它反映此 Class 对象所表示的类的指定公共构造方法
参数说明:参数为对应构造方法的数据类型的字节码文件对象,形如String.class或int.class;可变参数类型
(5)public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):表示获取类或者接口中的指定的构造方法
实例2
package demo; import java.lang.reflect.Constructor; public class Demo2 { public static void main(String[] args) throws Exception{ //方式1---public Constructor<?>[] getConstructors(),返回的是一个构造方法所在数组 //加"s"获取所有的公共的(public修饰的)构造方法 Constructor<?>[] constructors = person.getConstructors(); //遍历构造方法 for(Constructor con:constructors){ System.out.println(con); } System.out.println("---------------------"); //方式2 Constructor<?>[] dc = person.getDeclaredConstructors(); for(Constructor con:dc){ System.out.println(con); } System.out.println("----------------------"); //方式3---获取某一个公共的构造方法 Constructor<?> con = person.getConstructor(String.class,String.class); System.out.println(con); //方式4---获取某个构造方法,我们就获取个私有的方法 Constructor<?> dcr = person.getDeclaredConstructor(String.class,int.class); System.out.println(dcr); //了解一下打印的内容:public demo.Person(java.lang.String,int) } }动态的创建一个类的实例----不经过编译时期的检查(翻墙)
(6)public 类名 newInstance():
说明:可以直接通过Class的newInstance()的方法,特点:对没有参数的默认构造器初始化并创建对象
除了Class的此方法,还有没有其它的途径创建对象?当然有
Constructor类
理解上:其实类似于将int类型封装成Integer类那样,将构造方法封装成Constructor类(1)public T newInstance(Object... initargs):
说明:传递的是实际参数(可变参数),该方法等效于创建一个类的对象(动态)
实例3 创建对象动态和静态(公共的构造方法)
package demo; import java.lang.reflect.Constructor; public class Demo3 { public static void main(String[] args) throws Exception { //(1)静态 Person person = new Person(); //System.out.println(person); //(2)动态 Person person2 = Person.class.newInstance(); System.out.println(person==person2); //(3)动态 Class<?> person3 = Class.forName("demo.Person"); Constructor<?> dc = person3.getDeclaredConstructor(); Object obj = dc.newInstance();//最常用的,返回值也最特殊 //(4)动态 Class<? extends Person> class1 = person.getClass(); Constructor<? extends Person> dc1 = class1.getDeclaredConstructor(); Person person4 = dc1.newInstance(); } }
注意:(2)和(3)以及(4)的newInstance()方法的返回值
那么问题来了,私有的构造方法能否创建对象?
(2)public void setAccessible(boolean flag):在访问的时候取消java语言访问检查(强制性)---常常是私有的构造方法;常常"fla
dcee
g=true" ----在给构造创建实例对象之前就应该取消检查
实例4
package demo; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class Demo4 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //动态的创建类对象,并初始化(私有的和公共的) //1:私有的方式 String str="demo.Person"; Class<?> c = Class.forName(str); Constructor<?> dc = c.getDeclaredConstructor(String.class,int.class); dc.setAccessible(true);//私有的构造方法不能直接访问 Object obj = dc.newInstance("小王",27); System.out.println(obj);//调用Person类的toString()方法 //2:公共的方式 Constructor<?> con = c.getConstructor(String.class,String.class); Object ne = con.newInstance("小王","0012"); System.out.println(ne); } }
通过反射获取成员变量并使用:成员变量--->Field
(1)获取所有的公共的成员变量public Field[] getFields()
说明:所有的公共的可访问的字段,返回的是Field对象数组
(2)public Field[] getDeclaredFields()
说明:获取当前字节码文件对象中所有的公共的或者私有的字段
(3)public Field getField(String name)
说明:获取公共的指定的字段,参数为当前成员变量名称的字符串形式
(4)public Field getDeclaredField(String name)
说明:获取类或接口中已经声明的指定的字段(一般私有的)
注意1:如果给当前obj实例对象设置一个参数,将指定对象变量上此 Field对象表示的字段设置为指定的新值;
public void set(Object obj, Object value)----给obj实例对象里面的成员变量设置一个实际参数;obj为动态的对象(forName创建的形式)
注意2:如果想对私有成员变量设置值,必须在设置值之前取消Java语言的访问检查:Field类的方法---setAccessible(true);
注意3:输出每个对象不是地址的原因:多态
实例5
package demo; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; /** * 通过反射获取成员变量并使用 * 成员变量--->Field * * @author Orange * @version 1.8 */ public class Demo5 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //(1)创建Class对象 Class<?> person = Class.forName("demo.Person"); //(2)获取所有的公共的成员变量public Field[] getFields():所有的公共的可访问的字段,返回的是Field对象数组 Field[] fields = person.getFields(); //遍历 for(Field fie:fields){ System.out.println(fie); } System.out.println("--------------------------"); //(3)public Field[] getDeclaredFields():获取当前字节码文件对象中所有的公共的或者私有的字段 Field[] df = person.getDeclaredFields(); for(Field fie:df){ System.out.println(fie); } //(4)重点---获取单个公共的成员变量(Field类对象) //public Field getField(String name):获取公共的指定的字段,参数为当前成员变量名称"address" Field field = person.getField("age"); //(5)动态创建一个对象 Constructor<?> con = person.getConstructor(); Object obj = con.newInstance(); //有了Field对象,给当前obj实例对象设置一个参数 //将指定对象变量上此 Field对象表示的字段设置为指定的新值public void set(Object obj, Object value) //给obj实例对象里面的成员变量设置一个实际参数---->value field.set(obj, 27); System.out.println(obj); //(6)私有的成员变量 Field de = person.getDeclaredField("name"); de.setAccessible(true); de.set(obj, "小王"); System.out.println(obj); } }
调用对象的成员方法----Class类的方法
(1) public Method[] getDeclaredMethods():
说明:得到此类对象本身的所有方法(公共,受保护、默认、私有),但不包括继承其它的方法(不管什么方式)
(2) public Method[] getMethods():获取当前该字节码文件对象(Person.class)中自己本身以及它父类中所有的公共成员方法(包括继承)
说明:除了自身的公共方法以外,还有继承的公共方法
(3) public Method getMethod(String name,Class<?>... parameterTypes):指定公共成员方法
参数1:表示方法名的字符串形式
参数2:该方法的参数类型的Class对象(数据类型的class属性) String.class(非实参)
说明:返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法(无继承的方法,自身类中特有的公共方法)。
(4) public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
说明:得到该对象(无继承方法)反映此 Class 对象所表示的类或接口的指定已声明方法(可以私有化)
Method类
(1) public Object invoke(Object obj, Object... args)----对封装的方法进行调用→真正调用方法参数1:表示当前针对哪个以实例对象进行方法的调用----疑问静态方法不需要obj吧!!!
参数2:当前调用该方法的时候里面传递的实际参数
说明:唯一有参数的,参数需要指明调用的动态对象,然后传递参数才能调用此对象的方法。
注意:如果是私有的方法,必须取消Java语言的访问检查---主要针对私有的方法---setAccessible(true)
实例6 通过反射获取成员变量并使用,之前使用对象调用成员方法
package demo;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Demo6 {
/**
* 需求:
* 通过反射获取成员变量并使用,之前使用对象调用成员方法
* 类似:
* Person p = new Person() ;
* p.show() ;
*/
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
Class<?> person = Class.forName("demo.Person");
Constructor<?> con = person.getConstructor();
Object instance = con.newInstance();//动态的创建了一个对象
Method[] met = person.getMethods();
Method me = person.getMethod("method1");
Object inv = me.invoke(instance);
System.out.println(inv);
}
}
反射的应用
reflect_handler的应用---体会
动态代理:
我给你ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?
属性集合类----动态代理的形式
相关文章推荐
- Java程序员从笨鸟到菜鸟之(八)反射和代理机制
- Java程序员从笨鸟到菜鸟之(八)反射和代理机制
- Java程序员从笨鸟到菜鸟之(四十五)大话设计模式(九)迭代器模式和命令模式
- Java程序员从笨鸟到菜鸟之(八)反射和代理机制
- Java程序员从笨鸟到菜鸟之(八)反射和代理机制
- Java程序员从笨鸟到菜鸟之(四十五)大话设计模式(九)迭代器模式和命令模式
- Java程序员从笨鸟到菜鸟之(四十五)大话设计模式(九)迭代器模式和命令模式
- Java程序员从笨鸟到菜鸟之(八)反射和代理机制
- Java程序员从笨鸟到菜鸟之(八)反射和代理机制
- Java程序员从笨鸟到菜鸟之(八)反射和代理机制
- Java程序员从笨鸟到菜鸟之(八)反射和代理机制
- Java程序员从笨鸟到菜鸟之(八)反射和代理机制
- Java程序员从笨鸟到菜鸟全部博客目录
- Java程序员从笨鸟到菜鸟(二)Java实现冒泡排序、快速排序、插入排序、选择排序等基本排序方式
- Java程序员从笨鸟到菜鸟之(二十三)常见乱码解决以及javaBean基础知识
- Java程序员从笨鸟到菜鸟之(四十八)细谈struts2(十)ognl概念和原理详解
- Java程序员从笨鸟到菜鸟之(十七)CSS基础积累总结(下)
- Java程序员从笨鸟到菜鸟之(七十一)细谈struts2(十三)struts2实现文件上传和下载详解
- Java程序员从笨鸟到菜鸟之(三十)javascript弹出框、事件、对象化编程
- Java程序员从笨鸟到菜鸟之(一)开发环境搭建,基本语法,字符串,数组