JavaSE(十)之反射
开始接触的时候可能大家都会很模糊到底什么是反射,大家都以为这个东西不重要,其实很重要的,几乎所有的框架都要用到反射,增加灵活度。到了后面几乎动不动就要用到反射。
首先我们先来认识一下对象
学生----->抽象----->Student
表示学生 Student = .......
那我们的反射中的Class呢?
类型----->抽象----->Class(反射的入口破)
java.lang.class 表示java中的类型
Class c = Student.Class
Class c = int.Class
Class c =int[].Class
一、反射(Reflection)的概述
1.1、定义
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法 对于任意一个对象,都能够调用它的任意一个方法和属性, 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
即:在"运行时",通过反射机制可以动态获得到和该类型相关的各种信息。
java通常是先有类后有对象,有对象就可以调用方法或属性。反射其实是通过Class对象来调用类里面的方法。
通过反射可以调用私有方法和私有属性。大部分框架都是运用反射原理。
1.2、Class类型 java.lang.Class类
Class是对java中所有类型的抽象。即一个Class类型对象可以表示出java中任意一种类型。每种类型在加载到内存后,内存中都会生产一个与之对应的Class类型对象(有且只有一个),用来表示该类型。
每个类型都有且只有一个Class类型对象与之对应,通过这个Class类型对象就可以获得到该类型中的各种信息。Class类是Java反射的入口.。
1)表示基本类型
Class c = int.class;
System.out.println(c.isPrimitive());//true
System.out.println(c.getName());//int
注:其他基本类型的情况类似
2)表示类类型
注:s.getClass()方法返回的是变量s所指向对象的实现类型的Class对象。
Student s = new Student();
Class c1 = s.getClass();
Class c2 = Student.class;
System.out.println(c1 == c2);//true
//p指向的对象实际类型是Student
Person p = new Student();
Class c1 = p.getClass();//c1表示Student类型
Class c2 = Person.class;//c2表示Person类型
System.out.println(c1 == c2);//false
3)表示接口类型
Action a = new Student();
Class c1 = a.getClass();//c1表示Student类型
Class c2 = Action.class;//c2表示Action类型
System.out.println(c1 == c2);//false
System.out.println(c2.isInterface());//true
4)表示数组类型
int[] a = new int[4];
Class c1 = a.getClass();
Class c2 = int[].class;
System.out.println(c1 == c2);//true
System.out.println(c1.isArray());//true
Class c3 = c1.getComponentType();//c3表示该数组是使用什么类型声明出来的
System.out.println(c3.getName());//int
Student[] a = new Student[4];
Class c1 = a.getClass();
Class c2 = Student[].class;
System.out.println(c1 == c2);//true
System.out.println(c1.isArray());//true
Class c3 = c1.getComponentType();//c3表示该数组是使用什么类型声明出来的
System.out.println(c3.getName());//com.briup.test.Student
1.3、获取一个类类型的Class对象的三种方式
想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到
我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。
1)使用Class类中的forName方法获得
Class clazz1 = Class.forName("全限定类名"); //通过Class类中的静态方法forName,直接获取到一个类的字节码文件对象,此时该类还是源文件阶段,并没有变为字节码文件。
这种方法很灵活,只需一个String类型参数即可,而String类型的数据改变起来很容易,注意该方法是会抛出异常。
2)使用类名获得
Class clazz2 = Person.class; //当类被加载成.class文件时,此时Person类变成了.class,在获取该字节码文件对象,也就是获取自己, 该类处于字节码阶段。
3)使用对象调用getClass方法获得
Class clazz3 = p.getClass(); //通过类的实例获取该类的字节码文件对象,该类处于创建对象阶段。
getClass是Object中的final修饰的方法,每个对象都可以调用而且不能重写
注:以上三种方法获得的同一个对象(==比较),因为每个类型内存都有且只有一个Class类型对象。
1.4、反射机制中的常见类的含义
java.lang包下:
Class 类 对java中所有类型抽象而得来的
Package类 对java中所有包抽象而得来的
java.lang.reflect包下:
Modifier 类 对java中所有修饰符抽象而得来的
Field 类 对java中所有属性抽象而得来的
Method 类 对java中所有方法抽象而得来的
Constructor 类 对java中所有构造器抽象而得来的
Array 类 提供了对数组对象的动态访问
ParameterizedType接口 在反射中表示参数化类型
例如:List<String> Point<Long,Long>等这种带泛型的类型
二、反射机制获取类中的信息
2.1、使用Class类型对象获得类中的信息
1.获得该类所处的包的信息Student s = new Student();Class c = s.getClass();System.out.println(c.getPackage().getName());2.获得该类的修饰符信息//每个修饰符对应一个int值//如果有多个修饰符则int值相加Student s = new Student();Class c = s.getClass();System.out.println(c.getModifiers());System.out.println(Modifier.PUBLIC);System.out.println(Modifier.FINAL);3.获得该类的名字Student s = new Student();Class c = s.getClass();System.out.println(c.getName());4.获得该类的父类的Class对象Student s = new Student();Class c = s.getClass();//superclass表示其父类型的Class对象Class superclass = c.getSuperclass();System.out.println(superclass.getName());例如:Class c = Object.class;Class superclass = c.getSuperclass();System.out.println(superclass.getName());//运行报错,因为Object没有父类 例如://判断c1是不是c2的子类型//判断c3是不是c2的子类型Class c1 = Student.class;Class c2 = Person.class;Class c3 = String.classSystem.out.println(c2.isAssignableFrom(c1));//trueSystem.out.println(c2.isAssignableFrom(c3));//false5.获得该类所实现的接口类型的Class对象Student s = new Student();Class c = s.getClass();Class[] interfaces = c.getInterfaces();for(Class clazz:interfaces){System.out.println(clazz.getName());}例如://判断c1是不是c2的实现类//判断c3是不是c2的实现类Class c1 = Student.class;Class c2 = Action.class;Class c3 = String.classSystem.out.println(c2.isAssignableFrom(c1));//trueSystem.out.println(c2.isAssignableFrom(c3));//false6.获得该类中所有的属性Student s = new Student();Class c = s.getClass();Field[] declaredFields = c.getDeclaredFields();for(Field f:declaredFields){System.out.println(f.getModifiers());System.out.println(f.getType().getName());System.out.println(f.getName());}注:getDeclaredFields()方法返回类中声明的属性,包括私有的getFields()方法只返回类中public修饰的属性,包括继承的例如://获得某个指定的属性(也包括私有属性)Student s = new Student();Class c = s.getClass();Field f = c.getDeclaredField("score");System.out.println(f.getModifiers());System.out.println(f.getType().getName());System.out.println(f.getName());7.获得该类中所有的方法Student s = new Student();Class c = s.getClass();Method[] declaredMethods = c.getDeclaredMethods();for(Method m:declaredMethods){System.out.println(m.getModifiers());System.out.println(m.getReturnType().getName());System.out.println(m.getName());System.out.println(Arrays.toString(m.getParameterTypes()));System.out.println(Arrays.toString(m.getExceptionTypes()));}注:getDeclaredMethods()方法返回类中声明的方法,包括私有的getMethods()方法只返回类中public修饰的方法,包括继承的例如://获得某个指定的方法(也包括私有方法)Student s = new Student();Class c = s.getClass();Method m = c.getDeclaredMethod("print");System.out.println(m.getModifiers());System.out.println(m.getReturnType().getName());System.out.println(m.getName());System.out.println(Arrays.toString(m.getParameterTypes()));System.out.println(Arrays.toString(m.getExceptionTypes()));8.获得该类中所有的构造器Student s = new Student();Class c = s.getClass();Constructor[] declaredConstructors = c.getDeclaredConstructors();for(Constructor con:declaredConstructors){System.out.println(con.getModifiers());System.out.println(con.getName());System.out.println(Arrays.toString(con.getParameterTypes()));System.out.println(Arrays.toString(con.getExceptionTypes()));}注:getDeclaredConstructors()方法返回类中所有构造器getConstructors()方法只返回类中public修饰的构造器例如://获得某个指定的构造器(也包括私有构造器)Student s = new Student();Class c = s.getClass();Constructor con = c.getDeclaredConstructor(double.class);System.out.println(con.getModifiers());System.out.println(con.getName());System.out.println(Arrays.toString(con.getParameterTypes()));System.out.println(Arrays.toString(con.getExceptionTypes()));9.获得父类型中的泛型的真实类型因为泛型类的泛型参数在编译期会被擦除,所以我们不能再运行期间直接拿到该泛型的实际类型,但是可以通过子类的Class对象来获取父类的泛型类型。例如: 不通过子类不能获得泛型实际类型public class GenericTest<T,S>{public T name;public S say(T t,S s){return s;}}main:GenericTest<String,Integer> t = new GenericTest<String,Integer>();Class c = t.getClass();Field field = c.getDeclaredField("name");System.out.println(field.getType());System.out.println(field.getGenericType());//输出结果:class java.lang.ObjectTSystem.out.println("-------------------------");Method method = c.getMethod("say", Object.class,Object.class);System.out.println(method.getReturnType());System.out.println(method.getGenericReturnType());//输出结果:class java.lang.ObjectSSystem.out.println("-------------------------");System.out.println(Arrays.toString(method.getParameterTypes()));System.out.println(Arrays.toString(method.getGenericParameterTypes()));//输出结果:[class java.lang.Object, class java.lang.Object][T, S]例如: 通过子类可以获得父类中泛型的实际类型public class GenericTest<T,S>{public T name;public S say(T t,S s){return s;}}public class Sub entends GenericTest<String,Integer>{}main:Class c = Sub.class;//获得父类类型,包含泛型参数信息 Type superType = c.getGenericSuperclass();//判断父类类型是不是属于ParameterizedType类型//ParameterizedType表示带泛型的类型if(superType instanceof ParameterizedType){//强转,并调用方法获得泛型参数的实例类型ParameterizedType pt = (ParameterizedType)superType;Type[] actualTypeArguments = pt.getActualTypeArguments();//循环遍历,并强转为Class类型,因为Type接口中没有任何方法for(Type t:actualTypeArguments){Class clazz = (Class)t;System.out.println(clazz.getName());}}例如: 通过子类可以获得实现接口中泛型的实际类型 Class c = Sub.class;Type[] types = c.getGenericInterfaces();for(Type t:types){if(t instanceof ParameterizedType){ParameterizedType pt = (ParameterizedType)t;Type[] actualTypeArguments = pt.getActualTypeArguments();for(Type type:actualTypeArguments){Class clazz = (Class)type;System.out.println(clazz.getName());}}}10.获得类中的注解使用反射也可以获得类中的注解.(在之后的内容在来了解)
Class类型获取对象类中信息
2.2、反射的常用操作
1 public class Student{ 2 private long id; 3 private String name; 4 5 private static int age; 6 7 get/set 8 9 public static void say(){ 10 System.out.println("say.."); 11 }
1)使用反射的方式调用构造器创建类的对象
默认方式:必须调用无参构造器
Class c = Student.class;
Student s = (Student)c.newInstance();
通用方式:获得构造器对象,并调用该构造器
注:getConstructor方法和newInstance方法的参数都是可变参数
例如:获得无参构造器并调用创建对象
Class c = Student.class;
Constructor constructor = c.getConstructor();
Student o = (Student)constructor.newInstance();
System.out.println(o);
例如:获得有参构造器并调用创建对象
Class c = Student.class;
Constructor constructor = c.getConstructor(long.class,String.class);
Student o = (Student)constructor.newInstance(1L,"tom");
System.out.println(o);
2)使用反射的方式访问对象中的属性
例如:
Student s = new Student();
Class c = s.getClass();
Field[] declaredFields = c.getDeclaredFields();
for(Field f:declaredFields){
//设置私有属性可以被访问
f.setAccessible(true);
//判断属性是否为static,静态属性的访问不需要对象
if(Modifier.isStatic(f.getModifiers())){
System.out.println(f.getName() +" = "+f.get(null));
}else{
System.out.println(f.getName() +" = "+f.get(s));
}
}
注:Field类中的get方法可以获得属性值,set方法可以给属性设置值。
3)使用反射的方式调用对象中的方法
例如:
Student s = new Student();
Class c = s.getClass();
Method m1 = c.getMethod("setName",String.class);
//m1表示Student中的setName方法
//调用对象s中的m1方法,并且传参"tom"
//s.setName("tom");
m1.invoke(s, "tom");
Method m2 = c.getMethod("getName");
String name = (String)m2.invoke(s);
System.out.println("name = "+name);
//调用静态方法 不需要对象
Method m3 = c.getMethod("say");
m3.invoke(null);
4)使用反射的方式动态操作数组
注:
Object[] o1 = new int[1];//编译报错
long[] o2 = new int[1];//编译报错
int[] o3 = new int[1];//编译通过
Object[] o1 = new 任意引用类型[1];//编译通过
例如:
//要求:传任意类型"数组",把数组长度扩大1倍并返回//注意这里不能收Object[],//因为Object[] o = new Integer[4];编译通过//但是Object[] o = new int[4]; 编译报错//那么使用Object类中就可以接收任意类型的数组了public static Object arrayCopy(Object obj){//代码 }实现:public static Object arrayCopy(Object obj){Class c = obj.getClass();Object newArray = null;if(c.isArray()){int len = Array.getLength(obj);Class<?> type = c.getComponentType();newArray = Array.newInstance(type, len*2);for(int i=0;i<len;i++){Object value = Array.get(obj, i);Array.set(newArray, i, value);}}return newArray;}
数组长度扩大一倍
三、Class的API详解
3.1、通过字节码对象创建实例对象
3.2、获取指定构造器方法
constructor 如果没有无参构造,只有有参构造如何创建实例呢?看下面
总结上面创建实例对象:Class类的newInstance()方法是使用该类无参的构造函数创建对象, 如果一个类没有无参的构造函数, 就不能这样创建了,可以调用Class类的getConstructor(String.class,int.class)方法
取一个指定的构造函数然后再调用Constructor类的newInstance("张三",20)方法创建对象
获取全部构造方法
3.3、获取成员变量并使用
Field对象
获取指定成员变量
Class.getField(String)方法可以获取类中的指定字段(可见的), 如果是私有的可以用getDeclaedField("name")方法获取,通过set(obj, "李四")方法可以设置指定对象上该字段的值,
如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值
获取全部成员变量
3.4、获得方法并使用
Method
Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...)方法可以获取类中的指定方法,
如果为私有方法,则需要打开一个权限。setAccessible(true);
用invoke(Object, Object...)可以调用该方法,
跟上面同理,也能一次性获得所有的方法
3.5、获得该类的所有接口
Class[] getInterfaces():确定此对象所表示的类或接口实现的接口
返回值:接口的字节码文件对象的数组
3.6、获取指定资源的输入流
InputStream getResourceAsStream(String name)
return:一个 InputStream 对象;如果找不到带有该名称的资源,则返回 null
参数:所需资源的名称,如果以"/"开始,则绝对资源名为"/"后面的一部分。
四、两个实例来全面了解反射
实例1:
package corejava.test;import java.lang.reflect.Array; import java.lang.reflect.Constructor;class A{private int id;private String name="Tom";private A(int a,String name){id=a;}@Overridepublic String toString() {return "A [id=" + id + ", name=" + name + "]";} }public class Test1 {public static Object createObject(String classname) throws Exception {Class<?> name = Class.forName(classname);return createObject(name);}public static Object createObject(Class<?>c) throws Exception{Object object=null;try {object=c.newInstance();} catch (InstantiationException e) { // 如果此 Class 表示一个抽象类、接口、数组类、基本类型或 void; // 或者该类没有 null 构造方法; 或者由于其他某种原因导致实例化失败。// 2、数组类、基本类型 能够创建对象if(c.isArray()){object=Array.newInstance(c.getComponentType(),5);}else if(c.isPrimitive()){if(c == boolean.class){object=false;}else if(c==void.class){throw new Exception(c.getName()+"不能创建对象!");}else {object=0;}}else { // 3、没有 null 构造方法 Constructor<?>[] constructors = c.getConstructors();if(constructors.length==0) throw new Exception(c.getName()+"没有Public构造器!");Class<?>[] parameterTypes = constructors[0].getParameterTypes();Object[] parameters=new Object[parameterTypes.length];for(int i=0;i<parameters.length;i++){parameters[i]=createObject(parameterTypes[i]);}object=constructors[0].newInstance(parameters);} // 1、其他某种原因、void、抽象类、接口时抛出异常if(object==null)throw new Exception(c.getName()+"不能创建对象!");}return object;}public static void main(String[] args) throws Exception {System.out.println(createObject(A.class));System.out.println("ssss"); // System.out.println(new String()); // System.out.println("ssss"); }}
实例1
实例2:
package corejava.test;import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Parameter; import java.nio.file.spi.FileSystemProvider;import static java.lang.System.out;final class B{private int id;private String name="Tom";private static String mm="Tom";private B(int a,String name){id=a;}@Overridepublic String toString() {return "B [id=" + id + ", name=" + name + "]";}public int f(String name,A a){return id;} } public class Test2 {public static void printClass(Class<?> c) throws Exception{//1、包名;out.println(c.getPackage()+";");//2、修饰符 +class+类名{out.println(Modifier.toString(c.getModifiers())+" class "+c.getSimpleName()+" {");//3、修饰符 +属性类型+属性名;for(Field f:c.getDeclaredFields()){out.print("\t"+Modifier.toString(f.getModifiers())+" "+f.getType().getSimpleName()+" "+f.getName());f.setAccessible(true);if(Modifier.isStatic(f.getModifiers()))out.print(" = "+f.get(null));out.println(";");}//4、修饰符 +类名+( 参数类型+参数名字){ }for(Constructor<?> constructor:c.getDeclaredConstructors()){out.print("\t"+Modifier.toString(constructor.getModifiers())+" "+c.getSimpleName()+"("); Parameter[] ps = constructor.getParameters();for(int i=0;i<ps.length;i++){out.print(ps[i].getType().getSimpleName()+" "+ps[i].getName());if(i<ps.length-1)out.print(",");}out.println("){}");}out.println();//5、修饰符 +返回类型+方法名++( 参数类型+参数名字){ }for(Method m:c.getDeclaredMethods()){out.print("\t"+Modifier.toString(m.getModifiers())+" "+m.getReturnType().getSimpleName()+" "+m.getName()+"("); Parameter[] ps = m.getParameters();for(int i=0;i<ps.length;i++){out.print(ps[i].getType().getSimpleName()+" "+ps[i].getName());if(i<ps.length-1)out.print(",");}out.println("){}");out.println();}//6、}out.println("}");}public static void main(String[] args) throws Exception {printClass(Object.class);}}
实例2
觉得不错的“点个推荐”哦!
JavaSE(十)之反射相关推荐
- JavaSE(十六)——反射
文章目录 1. 概述 2. Class类 3. 获取Class对象的三种方式 4. 获取类的结构信息 5. 创建类的对象 6. 调用指定的方法 7. 反射操作泛型 1. 概述 Java可称为" ...
- 三十八,反射的应用:工厂模式
2019独角兽企业重金招聘Python工程师标准>>> 1.通过反射调用类中的方法 示例: Person类: package com.ares.demo;interface Info ...
- 《Go语言程序设计》读书笔记(十)反射
Go语言提供了一种机制在运行时更新变量和检查它们的值.调用它们的方法和它们支持的操作,但是在编译时并不知道这些变量的具体类型.这种机制被称为反射.反射也可以让我们将类型本身作为第一类的值类型处理. 在 ...
- 《Go 语言程序设计》读书笔记(十)反射
Go语言提供了一种机制在运行时更新变量和检查它们的值.调用它们的方法和它们支持的操作,但是在编译时并不知道这些变量的具体类型.这种机制被称为反射.反射也可以让我们将类型本身作为第一类的值类型处理. 在 ...
- JavaSE——单元测试、反射、注解、动态代理
文章目录 单元测试 单元测试概述 单元测试快速入门 单元测试常用注解 反射 反射概述 反射获取类对象 反射获取构造器对象 反射获取成员变量对象 反射获取方法对象 反射的作用-绕过编译阶段为集合添加数据 ...
- Android 源码系列之二十通过反射解决在HuaWei手机出现Register too many Broadcast Receivers的crash
转载请注明出处:http://blog.csdn.net/llew2011/article/details/79054457 Android开发适配问题一直是一个让人头疼的话题,由于国内很多厂商都有对 ...
- Java核心编程总结(十、反射),linux技术支持
1.基础回顾+面试 =========================================================================== 1.1单元测试 什么是单元测 ...
- JavaSE(十九)——equals() 和 == 的区别
文章目录 1. 不同数据类型中 == 的含义 2. equals()方法 3. 举例验证 1. 不同数据类型中 == 的含义 基本数据类型(原始数据类型) :byte,short,char,int,l ...
- JavaSE(十八)——IO流之字符流
文章目录 1. 概述 2. OutputStreamWriter 3. InputStreamReader 4. 字符流复制文本文件 5. FileWriter.FileReader 6. 高效的字符 ...
- JavaSE(十五)——注解
文章目录 1. 概述 2. 内置注解 3. 元注解 4. 自定义注解 1. 概述 不是程序本身,但可以对程序作出解释,可以被其他程序(比如:编译器)读取. 格式:@注释名(参数值) 使用范围:可以附加 ...
最新文章
- 利用 test 命令的测试功能
- 透过面试题,洞察Hbase 核心知识点
- 当你伤心时的飞鸽传书
- python autoitlibrary_AutoItLibrary
- CCF201409试题
- cout输出精确小数点
- C语言课设物业费管理系统(大作业)
- GD32VF103学习笔记(1)
- 第1章 SAAS-HRM系统概述与搭建环境
- 举例说明儿化音的作用_六年级语文下学期复习资料
- 菜鸟入门Docker
- 双系统之删除Linux
- 我的淘宝花名“九霄”
- .htaccess wp博客 静态网页 永久链接一步步来
- UDIMM、RDIMM和LRDIMM
- 目前国内常见医用显示器品牌
- office2016激活后还显示激活页面的解决办法
- 投保攻略:买车需要买哪些产品
- win10自带虚拟机安装centos实操(含参考博文)
- Live800:在线客服系统如何帮助企业创造持续的服务价值?
热门文章
- python语言入门m-python基础入门这一篇就够
- python urllib.request 爬虫 数据处理-python爬虫之json数据处理
- python发声-python写报警程序中的声音实现winsound
- python入门教程2word-python操作word入门
- python官方文档中文下载-python中文官方文档 PDF 下载
- libqrencode生成二维码图片的问题
- 题目1483:求最大最小数
- js流程图:aworkflow.js
- oracle数据库【表复制】insert into select from跟create table as select * from 两种表复制语句区别...
- 事务控制语句,begin,rollback,savepoint,隐式提交的SQL语句