反射的概述:
JAVA反射机制是在运行时将任何一个类的内部信息暴露出来,例如这个类的所有属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
反射是java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!
使用方法:
java.lang.Class:是反射的源头
通过运行时类的对象,调用其getClass方法,返回其运行时类
正常的顺序时通过类构建对象,反射是通过对象找到其所对应的类,进而调用这个类
创建的Persion类:包含注解、集成、接口、私有属性、私有方法等。
package D19;
/**
* @Author: wj
* @Date: 2018/11/25 8:35
* @Version 1.0
*/
@MyAnnotation(value = "annotation")
public class Persion extends Creature<String> implements Comparable,MyInterface{
public String name;
private int age;
public Persion(String name, int age) {
this.name = name;
this.age = age;
}
public Persion() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@MyAnnotation(value = "123")
public void show(){
System.out.println("我是一个人");
}
private void display(String nation){
System.out.println("我的国籍是:" +nation);
}
public static void info(){
System.out.println("中国人");
}
@Override
public String toString() {
return "Persion{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public int compareTo(Object o) {
return 0;
}
}
1.
一.获取Class的四种方法:
1. 调用运行时类本身
Class clazz1 = Persion.Class;
System.out.print(clazz1.getName());
2. 通过运行时类的对象创建
Persion persion = new Persion();
Class clazz2 = persion.getClass();
System.out.print(clazz2.getName());
3.通过运行时类的全类名路径
Class clazz3 = Class.forName("D19.Persion");
System.out.print(clazz3.getName());
4.通过类加载器
ClassLoader classLoader = this.getClass().getClassLoader();
Class clazz4 = classLoader.loadClass("D13.Persion");
System.out.print("clazz4.getName()");
二.Class 的运用
1.获取运行时类的属性:
属性的权限有别,有public、private、protected,不同权限的属性获取方法不同
下面提供两种方法:
//获取运行时类的属性
@Test
public void test1(){
Class clazz = Persion.class;
//getFields 只能获取到运行时类及其父类中权限为public的
Field[] fields = clazz.getFields();
//getDeclaredFields只能获取到运行时类本身声明的所有属性,包括private
Field[] fields2 = clazz.getDeclaredFields();
for(int i =0 ; i<fields2.length;i++){
System.out.println(fields2[i].getName());
}
}
2.各个属性的特征,包括权限修饰符、类型、变量名都可通过Class获取
//属性有 权限修饰符 类型 变量名
//获取属性各个部分的内容
@Test
public void test2(){
//getDeclaredFields只能获取到运行时类本身声明的所有属性
Class clazz = Persion.class;
Field[] fields2 = clazz.getDeclaredFields();
for(Field f:fields2){
//1.获取每个属性的权限修饰符
int i = f.getModifiers();
String str1 = Modifier.toString(i);
System.out.println(str1);
//2.获取每个属性的变量类型
Class type = f.getType();
System.out.println(type.getName());
//3.获取每个属性的变量名
System.out.print(f.getName());
System.out.println();
}
}
3.获取运行时类中的各种方法,同属性一样,不同权限的方法获取形式不同
与属性类似,获取方法也分为两种
@Test
public void test3(){
Class clazz = Persion.class;
//1.获取运行时类及其父类包括Object中所有的声明为Public的方法
Method[] methods = clazz.getMethods();
for(Method m :methods){
System.out.println(m);
}
//2.获取运行时类自身的方法不包括父类的,其中也包含权限为private的
methods = clazz.getDeclaredMethods();
for(Method m :methods){
System.out.println(m);
}
}
4.方法其他特征的获取,包括注解、权限修饰符、返回值类型、方法名、形参列表、抛出的异常等
以下通过Method[] methods = clazz.getMethods();获取
//注解,权限修饰符,返回值类型,方法名,形参列表,抛出的异常
@Test
public void test4(){
Class clazz =Persion.class;
Method[] methods = clazz.getDeclaredMethods();
for(Method m :methods){
//1.获取注解
Annotation[] ann = m.getAnnotations();
System.out.print(ann);
//2.权限修饰符
System.out.print(Modifier.toString(m.getModifiers()));
//3.返回值类型
Class returnType = m.getReturnType();
System.out.print(returnType.getName()+" ");
//4.方法名
System.out.print(m.getName()+" ");
//5.形参列表
System.out.print("(");
Class[] params = m.getParameterTypes();
for(Class p:params){
System.out.print(p.getName());
}
System.out.print(")");
//6.异常类型
Class[] exceptions = m.getExceptionTypes();
if(exceptions.length!=0){
System.out.println("throws ");
}
for(Class e:exceptions){
System.out.print(e.getName());
}
System.out.println();
}
}
5.类的泛型获取(JDBC常用)
//获取父类泛型(JDBC用到)
@Test
public void test5() throws ClassNotFoundException {
Class clazz = Class.forName("D19.Persion");
//获取带泛型的父类
Type type = clazz.getGenericSuperclass();
ParameterizedType param = (ParameterizedType) type;
Type[] args = param.getActualTypeArguments();
System.out.println(((Class)args[0]).getName());
}
6.获取实现接口
//获取实现的接口
@Test
public void test6(){
Class clazz = Persion.class;
Class[] interfaces = clazz.getInterfaces();
for(Class i:interfaces){
System.out.println(i.getName());
}
}
7.通过Class创建对象,并为属性赋值,以及调用各类方法
1)通过无参构造器创建
//使用反射创建对象,调用其中的方法(运行时类)
@Test
public void testReflection() throws Exception{
Class<Persion> clazz = Persion.class;
//1.创建clazz对应的运行时类(Persion)的对象
Persion p = clazz.newInstance();//必须有无参的构造方法
System.out.println(p);
//2.调用属性
Field field1 = clazz.getField("name");//public属性
//私有属性调用
Field field2 =clazz.getDeclaredField("age");
field2.setAccessible(true);//关键
field1.set(p,"L");
field2.set(p,22);
System.out.println(p);
//3.使用反射调用类的方法
Method method1 = clazz.getMethod("show");//public方法
method1.invoke(p);
//带参数的以及私有的(private)方法
Method method2 = clazz.getDeclaredMethod("display", String.class);
method2.setAccessible(true);//关键
//为参数赋值(注意invoke可变参数)
method2.invoke(p,"China");
//带返回值的
Method method3 = clazz.getMethod("toString");
Object returnVal = method3.invoke(p);
System.out.println(returnVal);
//静态方法
Method method4 = clazz.getMethod("info");
method4.invoke(p);
//也可以不用太对象
method4.invoke(Persion.class);
}
2)调用指定构造器
//调用指定构造器
@Test
public void test8() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
String className = "D19.Persion";
Class clazz = Class.forName(className);
Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
cons.setAccessible(true);
Persion p = (Persion) cons.newInstance("bxklx",20);
System.out.println(p);
}
8.通过ClassLoder读取配置文件
配置文件:
user=root;
password=123
读取方法:
ClassLoader classLoader = this.getClass().getClassLoader();
InputStream is = classLoader.getResourceAsStream("Jdbc.properties");
Properties properties = new Properties();
properties.load(is);
String user = properties.getProperty("user");
System.out.println(user);
结果:
以上就是我学习JAVA反射时用到的方法,对于反射用到的地方特别多,尤其是阅读框架源码时候,此外在通过Sql查询数据库获得对象时,也可通过反射构建实体对象,并未对象赋值。