一、反射机制
1、反射的定义:
在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以。
2、关于Class(类)
(1) Class是一个类,一个描述类的类(也就是描述类本身),封装了描述方法(Method),描述字段的(Filed),描述构造器的(Constructor)等属性。
(2) 对象反射可以得到的信息:某个类的数据成员名、方法和构造器、某个类到底实现了哪些接口。
(3) 对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。 一个 Class 对象包含了特定某个类的有关信息。
(4)Class 对象只能由系统建立对象。
(5) 一个类在 JVM 中只会有一个Class实例。
栗子:创建一个类。
public classPerson {
String name;private intage;publicPerson() {
System.out.println("无参构造器");
}public Person(String name, intage) {
System.out.println("有参构造器");this.name =name;this.age =age;
}publicString getName() {returnname;
}public voidsetName(String name) {this.name =name;
}public intgetAge() {returnage;
}public void setAge(intage) {this.age =age;
}
@OverridepublicString 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();
@Testpublic void testGetClass() throwsClassNotFoundException {
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 = newPerson();
clazz=p.getClass();
System.out.println("通过getClass(): " +clazz);
}
4、利用newInstance创建对象:调用的类必须有无参的构造器。
@Testpublic voidtestNewInstance()throwsClassNotFoundException, IllegalAccessException, InstantiationException {
Class clazz= Class.forName("com.java.reflection.Person");//使用Class类的newInstance()方法创建类的一个对象//实际调用的类的那个 无参数的构造器(这就是为什么写的类的时候,要写一个无参数的构造器,就是给反射用的)//一般的,一个类若声明了带参数的构造器,也要声明一个无参数的构造器
Object obj =clazz.newInstance();
System.out.println(obj);
}
5、ClassLoader类加载器
//ClassLoader类装载器
@Testpublic void testClassLoader1() throwsClassNotFoundException, 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方法
@Testpublic void testGetResourceAsStream() throwsClassNotFoundException, IOException {//5、关于类加载器的一个主要方法//调用getResourceAsStream 获取类路径下的文件对应的输入流
InputStream in = this.getClass().getClassLoader()
.getResourceAsStream("com/java/reflection/test.properties");
System.out.println("in: " +in);
Properties properties= newProperties();
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 classPersonInvoke {2 publicPersonInvoke() {3 }4
5 privateString method2() {6 return "Person private String method2";7 }8 }
1 public class StudentInvoke extendsPersonInvoke{2 private voidmethod1(Integer age) {3 System.out.println("Student private void method1, age=:" +age);4 }5 }
1 /**
2 * 获取当前类的父类中定义的私有方法3 * 直接调用getSuperclass()4 */
5 @Test6 public void testGetSuperClass() throwsException {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)
/*** 构造器:开发用的比较少*/@Testpublic void testConstructor() throwsClassNotFoundException, NoSuchMethodException,
IllegalAccessException, InvocationTargetException, InstantiationException {
String className= "com.java.reflection.Person";
Class clazz = (Class) Class.forName(className);//1.获取Constructor对象
Constructor[] constructors =(Constructor[]) Class.forName(className).getConstructors();//遍历
for (Constructorconstructor: constructors) {
System.out.println(constructor);
}
Constructor 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 @interfaceAgeValidator {intmin();intmax();
}
1 /**
2 * 通过反射才能获取注解3 */
4 @Test5 public void testAnnotation() throwsException {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 instanceofAgeValidator){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