转|java反射方法和使用详解
概述
反射机制是在运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意个对象,都能够调用它的任意一个方法。在java中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。反射是框架设计的灵魂,它功能很强大,我们学会了它就可以搭配很多东西一起使用,下面一起来学习使用反射吧!
使用Book类来练习反射,代码如下:
public class Book {
private Integer id;
private String name;
public Integer age;
public Book() {
System.out.println("Public 无参构造函数");
}
public Book(String name) {
System.out.println("Public 带参构造函数");
}
private Book(String name,Double price){
System.out.println("Private 带两参构造函数");
}
public void printAll(){
System.out.println("公开方法");
}
private void printOne(){
System.out.println("私有方法");
}
}
获取类的三种方式
若想使用反射,必须先得到代表类的字节码的Class对象,Class类用于表示.class文件(字节码)。
第一种:使用Class.forName
使用 Class.forName(String classPath)
时,请求参数classPath写需要反射的类名,一般是以包名.类名。
try {
Class clz = Class.forName("com.entity.Book");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
第二种:使用类名.class
使用这种方法时,需要知道有这个类。
Class clz = Book.class;
第三种:对象.getClass()
使用的前提是对象已经被实例化。
Book book = new Book();
Class clz = book.getClass();
总结:这三种方法各有千秋,我们一般使用第一种方式,在开发中,请按照自己的实际需求去使用。
获取构造函数
getDeclaredConstructors(); 获取所有的构造函数
getDeclaredConstructor(参数类型); 获取一个指定参数类型的构造函数
getConstructors(); 获取所有公共的构造函数
getConstructor(参数类型); 获取一个指定参数类型的、public修饰的构造函数
使用方法:
//获取所有的构造函数
Constructor[] constructors = clz.getDeclaredConstructors();
//获取单个所有的构造函数
try {
Constructor constructor =
clz.getDeclaredConstructor(String.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
//获取所有的公开构造函数
Constructor[] constructors1 = clz.getConstructors();
//获取单个公开构造函数
try {
Constructor constructor = clz.getConstructor(String.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
获取名字
返回类型:String,可以反射类名、方法名和构造函数名等等。
getName(); //获取全名 例如:com.bean.Book
getSimpleName() //获取类名 例如:Book
Class clz = Book.class;
String name1 = clz.getName();
String name2 = clz.getSimpleName();
获取包
返回类型:Package
Package aPackage = clz.getPackage();
获取接口
getInterfaces(),
返回类型:Class[] interfaces
Class[] interfaces = clz.getInterfaces();
获取父类/超类
getSuperclass()
返回类型:Class superclass
Class superclass = clz.getSuperclass();
实例化对象
语法糖:newInstance(Object initargs)
第一种方式
Class clz = Book.class;
Object obj = clz.newInstance(); //将创建一个无参book对象
第二种方式
Class clz = Book.class;
Constructor constructor = clz.getDeclaredConstructor(); //获得无参构造
Object obj = constructor.newInstance(); //实例化book对象
设置访问属性
clz.setAccessible(true) //可访问
clz.setAccessible(false) //不可访问
//默认是false
Field id = clz.getField("age"); //age字段
id.setAccessible(true); //设为可访问
id.setAccessible(false); //设为不可访问
获取方法
- getMethods():获取所有的公共方法,注意,它会将系统自带的方法也得到
- getMethod(String name):获取单个公共方法,由参数指定方法名
- getDeclaredMethods():获取所有的方法,注意:它不会获取系统自带的方法
- getDeclaredMethod(String name):获取单个的所有方法 参数是可指定方法名
Class clz = Class.forName("Book");
Method[] methods = clz.getMethods(); //获取所有的公共方法
for (Method method : methods) {
System.out.println(method.getName());
}
Method method = clz.getMethod("printAll"); // 获取单个公共方法
method.invoke(clz.newInstance(), null); // 调用方法
Method[] methods = clz.getDeclaredMethods(); //获取所有方法
for (Method method1 : methods) {
System.out.println(method1.getName());
}
Method method1 = clz.getDeclaredMethod("printOne"); //获取单个公共方法
System.out.println(method1.getName());
调用方法
method.invoke(Object obj,Object... args)
obj:如果是实例方法,则传入该方法的类对象;如果是静态方法,写null。
args:方法的参数值,没有写null,或不写都行
// 获取单个的public方法,无法获取private方法
Method method = clz.getMethod("printAll");
//使用方法
method.invoke(clz.newInstance(),null);
反射面试题
Q:Java反射创建对象效率高,还是new创建对象的效率高?
A: 通过new创建对象的效率比较高。通过反射时,先查找类资源,使用类加载器创建,过程比较繁琐,所以效率较低。
Q:Java反射的作用是?
A: 反射机制是在运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意个对象,都能够调用它的任意一个方法。在java 中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。
Q:哪里会用到反射机制?
A: 加载MySQL的驱动类,如Hibernate、MyBatis等框架中会使用。动态代理设计模式也采用了反射机制。
例1:加载MySQL的驱动类,Class.forName('com.mysql.jdbc.Driver.class');
例2:使用反射机制,根据这个字符串获得某个类的Class实例;
Q:反射机制的优缺点是?
A: 优点 能够运行时动态获取类的实例,提高灵活性;与动态编译结合。可以解耦,提高程序的可扩展性。
缺点 使用反射性能较低,需要解析字节码,将内存中的对象进行解析;相对不安全,破坏了封装性(因为通过反射可以获得私有方法和属性)
提升性能解决方案:通过setAccessible(true),关闭JDK的安全检查来提升反射速度。第一次反射后,会有缓存,下次反射会快很多。ReflflectASM工具类,通过字节码生成的方式加快反射速度
结束语
对于Java反射,您怎么看?欢迎参与话题互动讨论,分享你的观点和看法, 评论区留言哦,喜欢小编文章的朋友请点赞,谢谢您的参与!