前言 java基础学习之反射机制笔记
正文 反射机制概述 反射(Reflection),用于java上指的是可以于运行时加载,探知,使用编译期间完全知的classes。
换言之,java程序可以在加载一个运行时类时才得知名称的class,并获悉其完整构造,并生成其对象例或对其fields设值,或唤起(invoke)其method方法
例子1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 package com.c0okb.java;public class Person { private String name; public int age; @Override public String toString () { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}' ; } 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; } public Person (String name,int age) { this .name = name; this .age = age; } private Person (String name) { this .name = name; } public Person () { } public void show () { System.out.println("你好,我是一个人" ); } private String showNation (String nation) { System.out.println("我的国籍是" +nation); return nation; } }
一般情况下,直接使用new来创建一个类的对象,但是这样有一个问题,外部无法通过类的对象调用其内部的属性,方法。
1 2 3 4 5 6 7 8 9 10 11 12 public void test1 () { Person p1 = new Person("Tom" ,12 ); p1.age = 10 ; System.out.println("你好,我是一个人" ); }
使用反射情况下创建一个类的对象,可以通过反射调用对象指定的属性,方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public void test2 () throws Exception { Class clazz = Person.class ; Constructor cons = clazz.getConstructor(String.class ,int .class ) ; Object obj = cons.newInstance("Tom" ,12 ); Person p = (Person) obj; System.out.println(obj.toString()); Field age = clazz.getDeclaredField("age" ); age.set(p,10 ); System.out.println(p.toString()); Method show = clazz.getDeclaredMethod("show" ); show.invoke(p); System.out.println("************************************" ); Constructor cons1 = clazz.getDeclaredConstructor(String.class ) ; cons1.setAccessible(true ); Person p1 = (Person) cons1.newInstance("Jerry" ); System.out.println(p1); Field name = clazz.getDeclaredField("name" ); name.setAccessible(true ); name.set(p1,"Hanmeimei" ); System.out.println(p1); Method showNation = clazz.getDeclaredMethod("showNation" ,String.class ) ; showNation.setAccessible(true ); String nation = (String) showNation.invoke(p1,"中国" ); System.out.println(nation); }
question:通过直接new的方式或者反射的方式都可以调用公共的结构,一般使用哪个
建议:直接new方式
关于java.lang.Class类的理解
1 2 3 4 5 6 7 类的加载过程: 第一步:由Java编译器进行源代码编译,得到相应类的字节码.class文件。 第二步:生成class文件之后,通过ClassLoader类加载器加载进内存,此过程称为类的加载. 加载到内存中的类,我们就称为运行时类,此运行类就作为Class的一个实例Java字节码由JVM执行解释给目标计算机。 第三步,目标计算机将结果呈现给我们计算机用户;因此,Java并不是编译机制,而是解释机制.class文件才可以在不同平台上运行加载。
重点在于:加载到内存中的类,我们就称为运行时类,此运行类就作为Class的一个实例
1 Class clazz = Person.class ;
clazz此时为Person类的一个对象。
获得运行时类的四种方法 1 加载到内存中的运行时类,会缓存一定时间,在此时间内,我们可以通过不同的方式来获取此运行时类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public void test3 () throws Exception { Class<Person> clazz1 = Person.class ; System.out.println(clazz1); Person p1 = new Person(); Class clazz2 = p1.getClass(); System.out.println(clazz2); Class clazz3 = Class.forName("com.c0okb.java.Person" ); clazz3 = Class.forName("java.lang.String" ); System.out.println(clazz3); System.out.println(clazz1 == clazz2); System.out.println(clazz1 == clazz3); ClassLoader classLoader = ReflectionTest.class .getClassLoader () ; Class clazz4 = classLoader.loadClass("com.c0okb.java.Person" ); System.out.println(clazz4); System.out.println(clazz1 == clazz4); }
最常用的方法是forName() ,体现反射的动态性
1 2 3 4 5 6 Class clazz3 = Class.forName("com.c0okb.java.Person" ); clazz3 = Class.forName("java.lang.String" ); System.out.println(clazz3); System.out.println(clazz1 == clazz2); System.out.println(clazz1 == clazz3);
Class对象的种类 1 2 3 4 5 6 7 8 (1)class 外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类 (2)interface 接口 (3)[]:数组 (4)enum:枚举 (5)annotation:注解@interface (6)primitive type:基本数据类型 (7)void
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public void test4 () { Class c1 = Object.class ; System.out.println(c1); Class c2 = Comparable.class ; Class c3 = String[].class ; Class c4 = int [][].class ; Class c5 = ElementType.class ; Class c6 = Override.class ; System.out.println(c6); Class c7 = int .class ; Class c8 = void .class ; System.out.println(c8); Class c9 = Class.class ; int [] a = new int [10 ]; int [] b = new int [100 ]; Class c10 = a.getClass(); Class c11 = b.getClass(); System.out.println(c10 == c11); }
ClassLoader(类的加载器) Java类加载器是Java运行时环境的一部分,负责动态加载Java类到Java虚拟机的内存空间中。类通常是按需加载,即第一次使用该类时才加载。
PS:由于有了类加载器,Java运行时系统不需要知道文件与文件系统。学习类加载器时,掌握Java的委派概念很重要。
类加载器它是在虚拟机中完成的,负责动态加载Java类到Java虚拟机的内存空间中,在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。
例子2
创建一个类ClassLoaderTest
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class ClassLoaderTest { public void test1 () { ClassLoader classloader = ClassLoaderTest.class .getClassLoader () ; System.out.println(classloader); ClassLoader classLoader1 = classloader.getParent(); System.out.println(classLoader1); ClassLoader classLoader2 = classLoader1.getParent(); System.out.println(classLoader2); } .... }
利用类加载器读取配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package com.c0okb.java;import org.junit.Test;import java.io.FileInputStream;import java.io.InputStream;import java.util.Properties;public class ClassLoaderTest { public void test2 () throws Exception { Properties pros = new Properties(); ClassLoader classLoader = ClassLoaderTest.class .getClassLoader () ; InputStream is = classLoader.getResourceAsStream("src/jdbc.properties" ); pros.load(is); String user = pros.getProperty("user" ); String password = pros.getProperty("password" ); System.out.println("user = " +user+",password = " +password); } }
通过反射创建对应的运行时类的对象 一般情况下,使用newInstance()
来创建对应运行时类的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class NewInstanceTest { public void test1 () throws Exception { Class<Person> clazz = Person.class ; Person obj = clazz.newInstance(); System.out.println(obj); } ... }
反射的动态性 —- 重点 在上文说到java的动态性是由反射来体现,通过demo体现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package com.c0okb.java; import org.junit.Test;import java.util.Random;public class NewInstanceTest { public void test2 () throws Exception { for (int i=0 ;i<10 ;i++){ int num = new Random().nextInt(3 ); String classPath = "" ; switch (num){ case 0 : classPath = "java.util.Date" ; break ; case 1 : classPath = "java.lang.Object" ; break ; case 2 : classPath = "com.c0okb.java.Person" ; break ; } try { Object obj = getInstance(classPath); System.out.println(obj); } catch (Exception e) { e.printStackTrace(); } } } public Object getInstance (String classPath) throws Exception { Class clazz = Class.forName(classPath); return clazz.newInstance(); } }
1 2 3 4 public Object getInstance (String classPath) throws Exception { Class clazz = Class.forName(classPath); return clazz.newInstance(); }
创建一个方法getInstance() ,用于返回当前运行时类的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public void test2 () throws Exception { for (int i=0 ;i<10 ;i++){ int num = new Random().nextInt(3 ); String classPath = "" ; switch (num){ case 0 : classPath = "java.util.Date" ; break ; case 1 : classPath = "java.lang.Object" ; break ; case 2 : classPath = "com.c0okb.java.Person" ; break ; } try { Object obj = getInstance(classPath); System.out.println(obj); } catch (Exception e) { e.printStackTrace(); } } }
这段代码中,将随机生成不同类的对象,动态性在于这个对象的生成是在javac编译之后,、根据需求去灵活调用 ,上文的代码在编译后将会生成的字节码,在需求的特定情况下将灵活地生成不同类的对象。使用new编写的话情况如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public void test2 () throws Exception { for (int i=0 ;i<10 ;i++){ int num = new Random().nextInt(3 ); String classPath = "" ; switch (num){ case 0 : Date date = new Date(); system.out.println(date) break ; case 1 : Object object = new Object(); system.out.println(object); break ; case 2 : Person person = new Person(); system.out.println(person); break ; } } }
这样子将new的对象写死了,每次需求都需要重新编译,才能生效。
运行时类的属性,方法,构造器的获取与调用 demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 package com.c0okb.java1;@MyAnnotation (value = "Hi" )public class Person extends Creature <String > implements Comparable <String >,Myinterface { private String name; int age; public int id; public Person () {} private Person (String name) { this .name = name; } Person(String name,int age){ this .name = name; this .age = age; } @MyAnnotation private String show (String nation) { System.out.println("我的国籍是:" +nation); return nation; } @MyAnnotation public String display (String interests,int age) throws NullPointerException,ClassCastException { return interests+age; } @Override public int compareTo (String o) { return 0 ; } @Override public void info () { System.out.println("我是一个人" ); } private static void showDesc () { System.out.println("我是一个可爱的人" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package com.c0okb.java1;import java.io.Serializable;public class Creature <String > implements Serializable { private char gender; public double weight; private void breath () { System.out.println("生物呼吸" ); } public void eat () { System.out.println("生物吃东西" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package com.c0okb.java1;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import static java.lang.annotation.ElementType.*;import static java.lang.annotation.ElementType.LOCAL_VARIABLE;@Target ({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})@Retention (RetentionPolicy.RUNTIME)public @interface MyAnnotation { String value () default "hello" ; }
1 2 3 4 5 package com.c0okb.java1;public interface Myinterface { void info () ; }
获取运行时类的属性结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 package com.c0okb.java2;import com.c0okb.java1.Person;import org.junit.Test;import java.lang.reflect.Field;import java.lang.reflect.Modifier;public class FieldTest { public void test1 () { Class clazz = Person.class ; Field[] fields = clazz.getFields(); for (Field f:fields){ System.out.println(f); } Field[] declaredFields = clazz.getDeclaredFields(); for (Field f:declaredFields){ System.out.println(f); } } public void test2 () { Class clazz = Person.class ; Field[] declaredFields = clazz.getDeclaredFields(); for (Field f : declaredFields){ System.out.println(f); int modifier = f.getModifiers(); System.out.println(Modifier.toString(modifier)); Class type = f.getType(); System.out.println(type); String name = f.getName(); System.out.println(name+"\n" ); } } }
获取运行时类的方法结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 package com.c0okb.java2;import com.c0okb.java1.MyAnnotation;import com.c0okb.java1.Person;import org.junit.Test;import java.lang.annotation.Annotation;import java.lang.reflect.Method;import java.lang.reflect.Modifier;public class MethodTest { public void test1 () { Class clazz = Person.class ; Method[] methods = clazz.getMethods(); for (Method m:methods){ System.out.println(m); } Method[] declaredmethods = clazz.getDeclaredMethods(); for (Method dm: declaredmethods){ System.out.println(dm); } } public void test2 () throws Exception { Class clazz = Person.class ; Method[] declareMethods = clazz.getDeclaredMethods(); for (Method m:declareMethods){ Annotation[] annos = m.getAnnotations(); for (Annotation a : annos){ System.out.println(a); } System.out.print(Modifier.toString(m.getModifiers())+"\t" ); System.out.println(m.getReturnType()); System.out.print(m.getName()+ "\t" ); System.out.print("(" ); Class[] parameterTypes = m.getParameterTypes(); if (!(parameterTypes == null && parameterTypes.length ==0 )){ for (int i=0 ;i<parameterTypes.length;i++){ if (i == parameterTypes.length-1 ){ System.out.print(parameterTypes[i].getName() + " args_" + i); break ; } System.out.print(parameterTypes[i].getName() + " args_" + i + "," ); } } System.out.print(")" ); Class[] exceptionTypes = m.getExceptionTypes(); if (exceptionTypes.length > 0 ){ System.out.print(" throws " ); for (int i=0 ;i<exceptionTypes.length;i++){ if (i == exceptionTypes.length-1 ) { System.out.print(exceptionTypes[i].getName()); break ; } System.out.print(exceptionTypes[i].getName()+"," ); } } System.out.println("\n" ); } } }
获取运行时类的其他属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 package com.c0okb.java2;import com.c0okb.java1.Person;import org.junit.Test;import java.lang.annotation.Annotation;import java.lang.reflect.Constructor;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.util.function.Predicate;public class otherTest { public void test1 () { Class clazz = Person.class ; Constructor[] constructors = clazz.getConstructors(); for (Constructor c: constructors){ System.out.println(c); } System.out.println(); Constructor[] declareConstructors = clazz.getDeclaredConstructors(); for (Constructor c: declareConstructors){ System.out.println(c); } } public void test2 () { Class clazz = Person.class ; Class superclass = clazz.getSuperclass(); System.out.println(superclass); } public void test3 () { Class clazz = Person.class ; Type genericsuperclass = clazz.getGenericSuperclass(); ParameterizedType paramType = (ParameterizedType) genericsuperclass; Type[] actualTypeArguments = paramType.getActualTypeArguments(); System.out.println(((Class)actualTypeArguments[0 ]).getName()); } public void test5 () { Class clazz = Person.class ; Class[] interfaces = clazz.getInterfaces(); for (Class c: interfaces){ System.out.println(c); } System.out.println(); Class[] interfaces1 = clazz.getSuperclass().getInterfaces(); for (Class c : interfaces1){ System.out.println(c); } } public void test6 () { Class clazz = Person.class ; Package pack = clazz.getPackage(); } public void test7 () { Class clazz = Person.class ; Annotation[] annotations = clazz.getAnnotations(); for (Annotation annos : annotations){ System.out.println(annos); } } }
调用运行时类的属性,方法,构造器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 package com.c0okb.java2;import com.c0okb.java1.Person;import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;import org.junit.Test;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class Reflection { public void testField () throws Exception { Class clazz = Person.class ; Person p = (Person) clazz.newInstance(); Field id = clazz.getField("id" ); id.set(p,1001 ); int pId = (int ) id.get(p); System.out.println(pId); } public void testField1 () throws Exception { Class clazz = Person.class ; Person p = (Person) clazz.newInstance(); Field name = clazz.getDeclaredField("name" ); name.setAccessible(true ); name.set(p,"Tom" ); System.out.println(name.get(p)); } public void testMethod () throws Exception { Class clazz = Person.class ; Person p = (Person) clazz.newInstance(); Method show = clazz.getDeclaredMethod("show" ,String.class ) ; show.setAccessible(true ); Object returnValue = show.invoke(p,"China" ); System.out.println(returnValue); System.out.println("*********如何调用静态方法**********" ); Method showDesc = clazz.getDeclaredMethod("showDesc" ); showDesc.setAccessible(true ); Object returnValue1 = showDesc.invoke(Person.class ) ; System.out.println(returnValue1); } public void testConstructors () throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class clazz = Person.class ; Constructor constructor = clazz.getDeclaredConstructor(String.class ) ; constructor.setAccessible(true ); Person per = (Person) constructor.newInstance("Tom" ); System.out.println(per); } }