开发中要知道的Java反射机制要点
2017-12-06 10:36
85 查看
1.什么是反射?
正常面向对象是是通过类,对象,然后来操作属性方法。而反射是反过来,通过大Class类提供的相关的如Field,Method,Constructor等API来用对象反向操作属性,对象,类的相关信息。所以JAVA的反射可以理解为通过大Class相关属性来操作对象相关的问题。
反射的主要内容
* 1 Java反射机制概述
* 2 理解Class类并获取Class类的实例(掌握)
* 3 类的加载与ClassLoader的理解
* 4 通过反射创建运行时类的对象 (掌握)
* 5 通过反射获取运行时类的完整结构:所有的属性、方法、构造器、父类、接口、注解、父类的泛型、
* 6 通过反射调用运行时类的指定属性、指定方法、指定的构造器等 (掌握)
* 7 反射的应用:动态代理
反射主要功能如:
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理
2. 反射的实现(反射的主要体验是用Class类来实现的):
第一步:先获取运行时类,即获取Class的实例。
//三种方法可以获取Class的实例,即运行时类
//以Person类为例,知道运行时类。直接调用类的静态属性:.class
1. Class cls = Person.class
//调用Class类的静态方法:forName() ----使用频率最高
2. Class cls = Class.forName("com.cy.exe1.Person");//用大Class提供的forName方法。
//通过运行时类的对象,调用getClass()
3.Class cls = p.getClass(); //p是Person的对象
//通过类的加载器ClassLoader实现 (了解)
4.ClassLoader classLoader = this.getClass().getClassLoader();
Class clazz3 = classLoader.loadClass("com.robot.java.Person");
第二步:再创建运行类的对象
方法1. Class cls = Class.forName("com.cy.exe1.Person");//获取运行类
//创建运行类对象,通过调用Class里的newInstanc方法,返回值默认是Objcet类型,如果用
//Person来接收的话,要用强转符,要么获取运行类时用泛型指定类型。
Object obj = cls.newInstance(); 或者Person p = (Person)cls.newInstance;
注意:创建类的对象:调用Class对象的newInstance()方法
1)运行类必须有一个无参数的构造器。
2)类的构造器的访问权限需要足够(private抛异常)。
方法2. ①通过Class类的getDeclaredConstructor(Class … parameterTypes)取得本类的指定形参类型的构造器
//getConstructor主要区别是只能调用公有的,前者者可以调用全部的,同理后面方法属性也是。
Construtor cons = cls.getConstructor(String.class,int.class);
②向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。
Object obj = cons.newInstance("babe",13);//返回值默认Object,也可强转Person.
Person p = (Person)cons.newInstance("babe",13);
//这里的p不是Class的对象,而是Class的对象cls的对象,相当于Class对象的对象。所以p是不能直接调用Class里的方法的,它只是cls的操作对象。
第三步:使用反射,主要是通过Class提供的Field,Method,Constructor,来操作对象获取相关信息。
即:通过反射获取运行时类的完整结构Field,Method,Interface,Constructor,SuperClass,Annotation
Class cls = Person.class; //获取Class类的实例
Person p = (Person)cls.newInstance;//创建Class实例的对象
1.对于属性而言,反射通过调用Class类中的Field来获取运行类对象的属性操作。(因为运行类时Class的实例)
//调用属性的步骤:
// Field field = p.getname 错误,因为p不是Class的对象,cls才是。
//1.调用getDeclaredField(String fieldName);
Field field = cls.getDeclaredField("name");
//2.保证当前的属性是可访问的:setAccessible(true)
field.setAccessible(true);//设置为可见为true,才能可见私有的
//3.对于属性的赋值、获取
field.set(p, "lili");
System.out.println(field); //输出为:private java.lang.String com.cyg.exe1.Person.name
System.out.println(p);//重写了tostring后,Person [name=lili, age=13, Num=null]
String pName = (String) field.get(p); //get(Object obj),输出lili.
2.对于方法而言,反射通过调用Class类中的Method来获取运行类对象的方法操作
//1.getDeclaredMethod()获取指定方法名,指定形参列表的方法,只能获取当前运行时
类中声明的所有的方法。(不包含父类中的方法)。
Method m = clazz.getDeclaredMethod("play",String.class,int.class);
//2.setAccessable(true):保证此方法可访问
m.setAccessible(true);
//3.调用此方法.如下的invoke()方法的返回值即为invoke()调用者对应的方法的返回值。
//如果invoke()调用者对应的方法没有返回值,此invoke()返回null.
Object returnValue = m.invoke(p, "张三",1001);
3.Constructor等的指定调用。
3.理解java.lang.Class类。
* 1.Class类是反射的源头
* 2.java程序在经过编译(javac.exe)以后,会生成一个或多个字节码文件(.class),
* 然后执行java.exe命令,将指定的字节码文件加载到内存中(通过JVM的类的加载器v 加载的)。加载到内存中的字节码文件本身
* 该运行类本身就是Class的实例。
* 3. 加载到内存中的字节码文件对应的类,就称作运行时类。比如:Person类。
* 每一个加载到内存中的运行时类,都作为Class的实例。
* 4. 运行时类只被加载一次。
4.Java反射全过程详解:
1.先获取运行时类,即获取Class的实例或者说实例化Class
2.有了Class实例以后,可以做什么?
应用一:可以创建对应的运行时类的对象(重点)
应用二:获取对应的运行时类的完整的类的结构:属性、方法、构造器、包、父类、接口、泛型、注解、异常、 内部类。
应用三:调用对应的运行时类中指定的结构(某个指定的属性、方法、构造器)(重点)调用指定属性结构
5.反射:体现java语言的动态的特性。
public Object getInstance(String className) throws Exception{
Class clazz = Class.forName(className);
return clazz.newInstance();
}
}
6.创建对象的常见方式
1.调用构造器的方式 new
2.直接调用静态方法:runtime.getInstance(),Calendar.getInstance();
3.反射机制创建对象。
反射有关的API简介
1.反射实现的API简介
在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中
–Class类:代表一个类。
–Field 类:代表类的成员变量(成员变量也称为类的属性)。
–Method类:代表类的方法。
–Constructor 类:代表类的构造方法。
–Array类:提供了动态创建数组,以及访问数组的元素的静态方法
在java.lang.Object类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。
2.Class类是Reflection API 中的核心类,它有以下方法
–getName():获得类的完整名字。
–getFields():获得类的public类型的属性。
–getDeclaredFields():获得类的所有属性。
–getMethods():获得类的public类型的方法。
–getDeclaredMethods():获得类的所有方法。
-getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes参数指定方法的参数类型。
-getConstructors():获得类的public类型的构造方法。
•getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes参数指定构造方法的参数类型。
•newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
•(2)通过默认构造方法创建一个新对象:
•Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
•以上代码先调用Class类的getConstructor()方法获得一个Constructor 对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。
•(3)获得对象的所有属性:
•Field fields[]=classType.getDeclaredFields();
•Class 类的getDeclaredFields()方法返回类的所有属性,包括public、protected、默认和private访问级别的属性
(4)Method类的invoke(Object obj,Object args[])方法接收的参数必须为对象,如果参数为基本类型数据,必须转换为相应的包装类型的对象。invoke()方法的返回值总是对象,如果实际被调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相应的包装类型的对象,再将其返回
(5)Java中,无论生成某个类的多少个对象,这些对象都会对应于同一个Class对象。 要想使用反射,首先需要获得待处理类或对象所对应的Class对象。
3.案例:获取运行时类的完整结构
我们可以通过反射,获取对应的运行时类中所有的属性、方法、构造器、父类、接口、父类的泛型、包、注解、异常等。。。。
【典型题目1】
@Test
public void test1(){
Class clazz = Person.class;
//获取所有的方法
//getMethods():只能获取运行时类及其所有的父类中声明为public的方法
// Method[] methods = clazz.getMethods();
// for(Method m : methods){
// System.out.println(m);
// }
//getDeclaredMethods():只能获取当前运行时类中声明的所有的方法。(不包含父类中的方法)
Method[] methods = clazz.getDeclaredMethods();
for(Method m : methods){
System.out.println(m);
}
}
【典型题目2】
// 获取父类的泛型
//功能性代码 vs 逻辑性代码
@Test
public void test3() {
Class clazz = Person.class;
Type genericSuperclass = clazz.getGenericSuperclass();
// 强转为带具体泛型参数的Type类型
ParameterizedType paramType = (ParameterizedType) genericSuperclass;
// 返回泛型参数构成的数组
Type[] typeArguments = paramType.getActualTypeArguments();
System.out.println(((Class) typeArguments[0]).getName());
}
// 带泛型的父类
@Test
public void test2() {
Class clazz = Person.class;
Type genericSuperclass = clazz.getGenericSuperclass();
System.out.println(genericSuperclass);
}
// 父类
@Test
public void test1() {
Class clazz = Person.class;
Class superclass = clazz.getSuperclass();
System.out.println(superclass); }
}
正常面向对象是是通过类,对象,然后来操作属性方法。而反射是反过来,通过大Class类提供的相关的如Field,Method,Constructor等API来用对象反向操作属性,对象,类的相关信息。所以JAVA的反射可以理解为通过大Class相关属性来操作对象相关的问题。
反射的主要内容
* 1 Java反射机制概述
* 2 理解Class类并获取Class类的实例(掌握)
* 3 类的加载与ClassLoader的理解
* 4 通过反射创建运行时类的对象 (掌握)
* 5 通过反射获取运行时类的完整结构:所有的属性、方法、构造器、父类、接口、注解、父类的泛型、
* 6 通过反射调用运行时类的指定属性、指定方法、指定的构造器等 (掌握)
* 7 反射的应用:动态代理
反射主要功能如:
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理
2. 反射的实现(反射的主要体验是用Class类来实现的):
第一步:先获取运行时类,即获取Class的实例。
//三种方法可以获取Class的实例,即运行时类
//以Person类为例,知道运行时类。直接调用类的静态属性:.class
1. Class cls = Person.class
//调用Class类的静态方法:forName() ----使用频率最高
2. Class cls = Class.forName("com.cy.exe1.Person");//用大Class提供的forName方法。
//通过运行时类的对象,调用getClass()
3.Class cls = p.getClass(); //p是Person的对象
//通过类的加载器ClassLoader实现 (了解)
4.ClassLoader classLoader = this.getClass().getClassLoader();
Class clazz3 = classLoader.loadClass("com.robot.java.Person");
第二步:再创建运行类的对象
方法1. Class cls = Class.forName("com.cy.exe1.Person");//获取运行类
//创建运行类对象,通过调用Class里的newInstanc方法,返回值默认是Objcet类型,如果用
//Person来接收的话,要用强转符,要么获取运行类时用泛型指定类型。
Object obj = cls.newInstance(); 或者Person p = (Person)cls.newInstance;
注意:创建类的对象:调用Class对象的newInstance()方法
1)运行类必须有一个无参数的构造器。
2)类的构造器的访问权限需要足够(private抛异常)。
方法2. ①通过Class类的getDeclaredConstructor(Class … parameterTypes)取得本类的指定形参类型的构造器
//getConstructor主要区别是只能调用公有的,前者者可以调用全部的,同理后面方法属性也是。
Construtor cons = cls.getConstructor(String.class,int.class);
②向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。
Object obj = cons.newInstance("babe",13);//返回值默认Object,也可强转Person.
Person p = (Person)cons.newInstance("babe",13);
//这里的p不是Class的对象,而是Class的对象cls的对象,相当于Class对象的对象。所以p是不能直接调用Class里的方法的,它只是cls的操作对象。
第三步:使用反射,主要是通过Class提供的Field,Method,Constructor,来操作对象获取相关信息。
即:通过反射获取运行时类的完整结构Field,Method,Interface,Constructor,SuperClass,Annotation
Class cls = Person.class; //获取Class类的实例
Person p = (Person)cls.newInstance;//创建Class实例的对象
1.对于属性而言,反射通过调用Class类中的Field来获取运行类对象的属性操作。(因为运行类时Class的实例)
//调用属性的步骤:
// Field field = p.getname 错误,因为p不是Class的对象,cls才是。
//1.调用getDeclaredField(String fieldName);
Field field = cls.getDeclaredField("name");
//2.保证当前的属性是可访问的:setAccessible(true)
field.setAccessible(true);//设置为可见为true,才能可见私有的
//3.对于属性的赋值、获取
field.set(p, "lili");
System.out.println(field); //输出为:private java.lang.String com.cyg.exe1.Person.name
System.out.println(p);//重写了tostring后,Person [name=lili, age=13, Num=null]
String pName = (String) field.get(p); //get(Object obj),输出lili.
2.对于方法而言,反射通过调用Class类中的Method来获取运行类对象的方法操作
//1.getDeclaredMethod()获取指定方法名,指定形参列表的方法,只能获取当前运行时
类中声明的所有的方法。(不包含父类中的方法)。
Method m = clazz.getDeclaredMethod("play",String.class,int.class);
//2.setAccessable(true):保证此方法可访问
m.setAccessible(true);
//3.调用此方法.如下的invoke()方法的返回值即为invoke()调用者对应的方法的返回值。
//如果invoke()调用者对应的方法没有返回值,此invoke()返回null.
Object returnValue = m.invoke(p, "张三",1001);
3.Constructor等的指定调用。
3.理解java.lang.Class类。
* 1.Class类是反射的源头
* 2.java程序在经过编译(javac.exe)以后,会生成一个或多个字节码文件(.class),
* 然后执行java.exe命令,将指定的字节码文件加载到内存中(通过JVM的类的加载器v 加载的)。加载到内存中的字节码文件本身
* 该运行类本身就是Class的实例。
* 3. 加载到内存中的字节码文件对应的类,就称作运行时类。比如:Person类。
* 每一个加载到内存中的运行时类,都作为Class的实例。
* 4. 运行时类只被加载一次。
4.Java反射全过程详解:
1.先获取运行时类,即获取Class的实例或者说实例化Class
2.有了Class实例以后,可以做什么?
应用一:可以创建对应的运行时类的对象(重点)
应用二:获取对应的运行时类的完整的类的结构:属性、方法、构造器、包、父类、接口、泛型、注解、异常、 内部类。
应用三:调用对应的运行时类中指定的结构(某个指定的属性、方法、构造器)(重点)调用指定属性结构
5.反射:体现java语言的动态的特性。
public Object getInstance(String className) throws Exception{
Class clazz = Class.forName(className);
return clazz.newInstance();
}
}
6.创建对象的常见方式
1.调用构造器的方式 new
2.直接调用静态方法:runtime.getInstance(),Calendar.getInstance();
3.反射机制创建对象。
反射有关的API简介
1.反射实现的API简介
在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中
–Class类:代表一个类。
–Field 类:代表类的成员变量(成员变量也称为类的属性)。
–Method类:代表类的方法。
–Constructor 类:代表类的构造方法。
–Array类:提供了动态创建数组,以及访问数组的元素的静态方法
在java.lang.Object类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。
2.Class类是Reflection API 中的核心类,它有以下方法
–getName():获得类的完整名字。
–getFields():获得类的public类型的属性。
–getDeclaredFields():获得类的所有属性。
–getMethods():获得类的public类型的方法。
–getDeclaredMethods():获得类的所有方法。
-getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes参数指定方法的参数类型。
-getConstructors():获得类的public类型的构造方法。
•getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes参数指定构造方法的参数类型。
•newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
•(2)通过默认构造方法创建一个新对象:
•Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
•以上代码先调用Class类的getConstructor()方法获得一个Constructor 对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。
•(3)获得对象的所有属性:
•Field fields[]=classType.getDeclaredFields();
•Class 类的getDeclaredFields()方法返回类的所有属性,包括public、protected、默认和private访问级别的属性
(4)Method类的invoke(Object obj,Object args[])方法接收的参数必须为对象,如果参数为基本类型数据,必须转换为相应的包装类型的对象。invoke()方法的返回值总是对象,如果实际被调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相应的包装类型的对象,再将其返回
(5)Java中,无论生成某个类的多少个对象,这些对象都会对应于同一个Class对象。 要想使用反射,首先需要获得待处理类或对象所对应的Class对象。
3.案例:获取运行时类的完整结构
我们可以通过反射,获取对应的运行时类中所有的属性、方法、构造器、父类、接口、父类的泛型、包、注解、异常等。。。。
【典型题目1】
@Test
public void test1(){
Class clazz = Person.class;
//获取所有的方法
//getMethods():只能获取运行时类及其所有的父类中声明为public的方法
// Method[] methods = clazz.getMethods();
// for(Method m : methods){
// System.out.println(m);
// }
//getDeclaredMethods():只能获取当前运行时类中声明的所有的方法。(不包含父类中的方法)
Method[] methods = clazz.getDeclaredMethods();
for(Method m : methods){
System.out.println(m);
}
}
【典型题目2】
// 获取父类的泛型
//功能性代码 vs 逻辑性代码
@Test
public void test3() {
Class clazz = Person.class;
Type genericSuperclass = clazz.getGenericSuperclass();
// 强转为带具体泛型参数的Type类型
ParameterizedType paramType = (ParameterizedType) genericSuperclass;
// 返回泛型参数构成的数组
Type[] typeArguments = paramType.getActualTypeArguments();
System.out.println(((Class) typeArguments[0]).getName());
}
// 带泛型的父类
@Test
public void test2() {
Class clazz = Person.class;
Type genericSuperclass = clazz.getGenericSuperclass();
System.out.println(genericSuperclass);
}
// 父类
@Test
public void test1() {
Class clazz = Person.class;
Class superclass = clazz.getSuperclass();
System.out.println(superclass); }
}
相关文章推荐
- 作为开发人员,你必须要知道的在线工具
- 网络干货,无论是运维还是开发都要知道的网络知识系列之(一)
- PHP开发一定要知道Github上的PHP资源汇总大全
- linux驱动开发要知道的那些知识(一)--module,内存管理
- Java开发一定要知道的日志性能那些事
- Android TV开发总结(一)构建一个TV app前要知道的事儿
- web前端开发的你必须要知道的“级联”问题
- 微信小程序:开发之前要知道的三件事
- iOS开发之调试技巧Xcode7中你一定要知道的炸裂调试神技、Address Sanitizer EXC_BAD_ACCESS
- 网络干货,无论是运维还是开发都要知道的网络知识系列之(七)
- Web开发人员必须要知道的浏览器知识
- Android TV开发总结(一)构建一个TV app前要知道的事儿
- 一定要知道的9段高效率开发PHP程序的代码
- linux驱动开发要知道的那些知识(二)------list内核链表
- []快速开发]最常用的正则表达式--你一定要知道
- 网络干货,无论是运维还是开发都要知道的网络知识系列之(三)
- linux驱动开发要知道的那些知识(一)--module,内存管理
- 网络干货,无论是运维还是开发都要知道的网络知识系列
- 大数据开发要知道的关于AVRO的知识