Java的反射机制
Posted 小潘同学
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java的反射机制相关的知识,希望对你有一定的参考价值。
一、反射机制
1、反射的定义:
在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以。
2、关于Class(类)
(1) Class是一个类,一个描述类的类(也就是描述类本身),封装了描述方法(Method),描述字段的(Filed),描述构造器的(Constructor)等属性。
(2) 对象反射可以得到的信息:某个类的数据成员名、方法和构造器、某个类到底实现了哪些接口。
(3) 对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。 一个 Class 对象包含了特定某个类的有关信息。
(4)Class 对象只能由系统建立对象。
(5) 一个类在 JVM 中只会有一个Class实例。
栗子:创建一个类。
public class Person { String name; private int age; public Person() { System.out.println("无参构造器"); } public Person(String name, int age) { System.out.println("有参构造器"); this.name = name; this.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; } @Override public String toString() { return "Person{" + "name=\'" + name + \'\\\'\' + ", age=" + age + \'}\'; } }
3、获取反射机制类的三种方法:
想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。获取字节码文件对象[反射对象]的三种方式:
1、通过Class类中的静态方法forName,直接获取到一个类的字节码文件对象,此时该类还是源文件阶段,并没有变为字节码文件。
Class clazz1 = Class.forName("全限定类名");2、当类被加载成.class文件时,此时Person类变成了.class,在获取该字节码文件对象,也就是获取自己, 该类处于字节码阶段。
Class clazz2 = Person.class;
3、通过类的实例获取该类的字节码文件对象,该类处于创建对象阶段
Class clazz3 = p.getClass();
@Test public void testGetClass() throws ClassNotFoundException { Class clazz = null; //1 通过全类名获取,用的比较多,但可能抛出ClassNotFoundException异常 clazz = Class.forName("com.java.reflection.Person"); System.out.println("通过全类名获取: " + clazz); //1 直接通过类名.Class的方式得到 clazz = Person.class; System.out.println("通过类名: " + clazz); //2 通过对象的getClass()方法获取,这个使用的少(一般是传的是Object,不知道是什么类型的时候才用) Object p = new Person(); clazz = p.getClass(); System.out.println("通过getClass(): " + clazz); }
4、利用newInstance创建对象:调用的类必须有无参的构造器。
@Test public void testNewInstance() throws ClassNotFoundException, IllegalAccessException, InstantiationException { Class clazz = Class.forName("com.java.reflection.Person"); //使用Class类的newInstance()方法创建类的一个对象 //实际调用的类的那个 无参数的构造器(这就是为什么写的类的时候,要写一个无参数的构造器,就是给反射用的) //一般的,一个类若声明了带参数的构造器,也要声明一个无参数的构造器 Object obj = clazz.newInstance(); System.out.println(obj); }
5、ClassLoader类加载器
// ClassLoader类装载器 @Test public void testClassLoader1() throws ClassNotFoundException, IOException { //1、获取一个系统的类加载器 ClassLoader classLoader = ClassLoader.getSystemClassLoader(); System.out.println("系统的类加载器-->" + classLoader); //2、获取系统类加载器的父类加载器(扩展类加载器(extensions classLoader)) classLoader = classLoader.getParent(); System.out.println("扩展类加载器-->" + classLoader); //3、获取扩展类加载器的父类加载器 //输出为Null,无法被Java程序直接引用 classLoader = classLoader.getParent(); System.out.println("启动类加载器-->" + classLoader); //4、测试当前类由哪个类加载器进行加载 ,结果就是系统的类加载器 classLoader = Class.forName("com.java.reflection.Person").getClassLoader(); System.out.println("当前类由哪个类加载器进行加载-->"+classLoader); //5、测试JDK提供的Object类由哪个类加载器负责加载的 classLoader = Class.forName("java.lang.Object").getClassLoader(); System.out.println("JDK提供的Object类由哪个类加载器加载-->" + classLoader); }
5.1 getResourceAsStream方法
@Test public void testGetResourceAsStream() throws ClassNotFoundException, IOException { //5、关于类加载器的一个主要方法 //调用getResourceAsStream 获取类路径下的文件对应的输入流 InputStream in = this.getClass().getClassLoader() .getResourceAsStream("com/java/reflection/test.properties"); System.out.println("in: " +in); Properties properties = new Properties(); properties.load(in); String driverClass = properties.getProperty("dirver"); String jdbcUrl = properties.getProperty("jdbcUrl"); //中文可能会出现乱码,需要转换一下 String user = new String(properties.getProperty("user").getBytes("ISO-8859-1"), "UTF-8"); String password = properties.getProperty("password"); System.out.println("diverClass: "+driverClass); System.out.println("user: " + user); }
6、invoke方法
1 public class PersonInvoke { 2 public PersonInvoke() { 3 } 4 5 private String method2() { 6 return "Person private String method2"; 7 } 8 }
1 public class StudentInvoke extends PersonInvoke{ 2 private void method1(Integer age) { 3 System.out.println("Student private void method1, age=:" +age); 4 } 5 }
1 /** 2 * 获取当前类的父类中定义的私有方法 3 * 直接调用getSuperclass() 4 */ 5 @Test 6 public void testGetSuperClass() throws Exception { 7 8 String className = "com.java.reflection.StudentInvoke"; 9 10 Class clazz = Class.forName(className); 11 Class superClazz = clazz.getSuperclass(); 12 13 System.out.println(superClazz); 14 //输出结果:class com.java.reflection.PersonInvoke 15 }
7、构造器(Constructor)
/** * 构造器:开发用的比较少 */ @Test public void testConstructor() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { String className = "com.java.reflection.Person"; Class<Person> clazz = (Class<Person>) Class.forName(className); //1.获取Constructor对象 Constructor<Person>[] constructors = (Constructor<Person>[]) Class.forName(className).getConstructors(); // 遍历 for (Constructor<Person> constructor: constructors) { System.out.println(constructor); } Constructor<Person> constructor = clazz.getConstructor(String.class, Integer.class); System.out.println("指定的-->" + constructor); //2.调用构造器的newInstance()方法创建对象 Object obj= constructor.newInstance("changwen", 11); }
8、注解(Annotation)
基本的 Annotation
• 使用 Annotation时要在其前面增加@符号,并把该Annotation 当成一个修饰符使用.用于修饰它支持的程序元素• 三个基本的Annotation:–@Override:限定重写父类方法,该注释只能用于方法–@Deprecated:用于表示某个程序元素(类,方法等)已过时–@SuppressWarnings:抑制编译器警告.
@Retention(RetentionPolicy.RUNTIME) //运行时检验 @Target(value = {ElementType.METHOD}) //作用在方法上 public @interface AgeValidator { int min(); int max(); }
1 /** 2 * 通过反射才能获取注解 3 */ 4 @Test 5 public void testAnnotation() throws Exception { 6 7 //这样的方式不能使用注解 8 /** Person3 person3 = new Person3(); 9 person3.setAge(10);*/ 10 11 String className = "com.java.reflection.Person3"; 12 Class clazz = Class.forName(className); 13 Object obj = clazz.newInstance(); 14 15 Method method = clazz.getDeclaredMethod("setAge",Integer.class); 16 int val =40; 17 18 //获取注解 19 Annotation annotation = method.getAnnotation(AgeValidator.class); 20 if (annotation != null){ 21 if (annotation instanceof AgeValidator){ 22 AgeValidator ageValidator = (AgeValidator) annotation; 23 24 if (val< ageValidator.min() || val>ageValidator.max()){ 25 throw new RuntimeException("数值超出范围"); 26 } 27 } 28 } 29 30 method.invoke(obj, val); 31 System.out.println(obj); 32 }
原文转载于:https://www.cnblogs.com/bojuetech/p/5896551.html
以上是关于Java的反射机制的主要内容,如果未能解决你的问题,请参考以下文章