反射
反射体现运行时的动态性
public class NewInstance1 {
//体现反射的动态性
public static void main(String[] args) throws Exception {
int i = new Random().nextInt(3);
String classPath="";
switch (i){
case 0:
classPath="com.etime01.Person";
break;
case 1:
classPath="java.util.Date";
break;
case 2:
classPath="java.lang.Object";
break;
}
Object instance = getInstance(classPath);
System.out.println(instance);
}
/*
创建一个指定类的对象
classPath:指定类的全类名
*/
public static Object getInstance(String classPath) throws Exception {
Class clazz = Class.forName(classPath);
return clazz.newInstance();
}
}
疑问1
通过直接new对象的方式或者反射的方式都可以调用公共的结构,开发中到底用哪个?
建议new 的方式,如果在编译时不能确定创建哪一个类的对象,当出现这种情况,就用反射的方式创建对象。
疑问2
反射可以调用类的私有属性和方法,是否和封装性有矛盾?
不矛盾,封装性的意思是,调用public修饰的的方法或者属性就行,private修饰的用不着,不建议调私有的方法或属性,但是还是要调取私有的,就可以用反射去调用私有的方法或属性。
关于java.lang.Class类的理解
- 类的加载过程:
程序经过javac.exe命令后,会生成一个或多个字节码文件(.class结尾)。接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就成为类的加载。加载内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例。
- 换句话说,Class的实例就对应着一个运行时类。
- 加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式来获取此运行时类。
获取Class的实例的方式(重点)
public class RefilectionTest {
//获取Class的实例的方式
public static void main(String[] args) throws ClassNotFoundException {
//方式一:调用运行时类的属性:.class
//写死了,不灵活
Class clazz1 = Person.class;
System.out.println(clazz1);
//方式二:通过运行时类的对象,调用getClass()
//都有对象了,没必要反射
Person p1 = new Person();
Class clazz2 = p1.getClass();
System.out.println(clazz2);
//方式三:调用Class的静态方法:for(String classPath)
//最常用 体现反射的动态性
Class clazz3 = Class.forName("com.etime01.Person");
System.out.println(clazz3);
//方式四:使用类的加载器:ClassLoader(了解)
ClassLoader classLoader = RefilectionTest.class.getClassLoader();
Class clazz4 = classLoader.loadClass("com.etime01.Person");
System.out.println(clazz4);
System.out.println(clazz1==clazz2);//true
System.out.println(clazz1==clazz3);//true
System.out.println(clazz1==clazz4);//true
}
}
Class实例可以是哪些结构的说明:
Class类不仅是运行时类,也可以是一些结构
public class RefilectionTest1 {
public static void main(String[] args){
//Class实例可以是哪些结构的说明:
Class c1 = Object.class;
Class c2 = Comparable.class;//接口
Class c3 = String[].class;
Class c4 = int[][].class;
Class c5 = ElementType.class;//枚举类
Class c6 = Override.class;//注解
Class c7 = int.class;
Class c8 = void.class;
Class c9 = Class.class;
int[] a = new int[10];
int[] b = new int[100];
Class c10 = a.getClass();
Class c11 = b.getClass();
//是要元素类型和维度一样,就是同一个Class
System.out.println(c10 == c11);//true
}
}
ClassLoader读取配置文件.properties
public class ClassLoadTest {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
//读取配置文件方式一 此时的配置文件在当前的module下
// FileInputStream fileInputStream = new FileInputStream("jdbc.properties");
// properties.load(fileInputStream);
//读取配置文件方式二:使用ClassLoader
//配置文件默认为当前module下的src下
//获取类加载器
ClassLoader classLoader = ClassLoadTest.class.getClassLoader();
//通过类加载器获得资源输入流
InputStream resourceAsStream = classLoader.getResourceAsStream("jdbc.properties");
//配置文件加载
properties.load(resourceAsStream);
String username = properties.getProperty("username");
String password = properties.getProperty("password");
System.out.println(username+"="+password);
}
}
运行结果
通过反射创建运行时类的对象(重点)
newInstance()方法
/**
* 通过反射创建对应的运行时类的对象
*/
public class NewInstance {
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
Class<Person> clazz = Person.class;
/**
* newInstance:调用此方法,调用运行时类的对象
* 这里调用的是无参构造器
* 要想此方法正常的创建运行时类的对象,要求:
* 1.运行时类必须提供空参的构造器
* 2.空参的构造器的访问权限得够。通常设置为public
*
* 在javabean中要求提供一个public的空参构造器。原因:
* 1.便于通过反射,创建运行时类的对象
* 2.便于子类继承此运行时类,默认调用super()时,保证父类有此构造器
*/
Person obj = clazz.newInstance();
System.out.println(obj);
}
}
体会反射的动态性
//反射的动态性
public class NewInstance1 {
public static void main(String[] args) throws Exception {
int i = new Random().nextInt(3);
String classPath="";
switch (i){
case 0:
classPath="com.etime01.Person";
break;
case 1:
classPath="java.util.Date";
break;
case 2:
classPath="java.lang.Object";
break;
}
Object instance = getInstance(classPath);
System.out.println(instance);
}
/*
创建一个指定类的对象
classPath:指定类的全类名
*/
public static Object getInstance(String classPath) throws Exception {
Class clazz = Class.forName(classPath);
return clazz.newInstance();
}
}
获取运行时类的完整结构
获取属性
/**
* 获取当前运行时类的属性结构
*/
public class FieldTest {
public static void main(String[] args) {
Class clazz = Person.class;
//getFields():获取当前运行时类及其父类中public修饰的属性
Field[] fields = clazz.getFields();
for (Field f:fields){
System.out.println(f);
}
System.out.println("---------------------");
//getDeclaredFields():获取当前运行时类中声明的所有属性 (不包含父类中声明的属性)
Field[] declaredFields = clazz.getDeclaredFields();
for (Field f:declaredFields){
System.out.println(f);
}
}
}
获取属性的各种结构(了解)
/**
* 获取当前运行时类的属性结构
*/
public class FieldTest02 {
public static void main(String[] args) {
Class clazz = Person.class;
Field[] declaredFields = clazz.getDeclaredFields();
//获取属性结构的权限修饰符 数据类型 变量名
for (Field f:declaredFields){
//1.权限修饰符
//返回的int类型的数字
//常见的 0代表默认 1代表public 2代表private 4代表protected 8代表static
int modifier = f.getModifiers();
System.out.println(modifier);
//2.数据类型
Class type = f.getType();
System.out.println(type.getName());//如果没有.getName()方法,得到的就是一个类,不是你想要的得到的东西
//3.变量名
String name = f.getName();
System.out.println(name);
}
}
获取方法
public class MethodTest {
public static void main(String[] args) {
Class clazz = Person.class;
//getMethods():获取当前运行时类及其父类中public修饰的方法
Method[] methods = clazz.getMethods();
for (Method m:methods){
System.out.println(m);
}
//getMethods():获取当前运行时类中声明的所有方法(不包含父类中声明的方法)
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m:declaredMethods){
System.out.println(m);
}
}
}
获取方法的各种结构(了解)
public class MethodTest02 {
public static void main(String[] args) {
//获取权限修饰符 返回值类型 方法名(参数类型1 形参1,...)
Class clazz = Person.class;
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m:declaredMethods){
//1.getAnnotations():获取方法声明的注解
Annotation[] annotations = m.getAnnotations();
for (Annotation a : annotations){
System.out.println(a);
}
//2.getModifiers():获取权限修饰符
//Modifier 修饰符
int modifiers = m.getModifiers();
System.out.println(Modifier.toString(modifiers));
//3.getReturnType():获取返回值类型
Class returnType = m.getReturnType();
String name = returnType.getName();//如果没有.getName()方法,得到的就是一个类,不是你想要的得到的东西
System.out.println(name);
//4.getName():获取方法名
String name1 = m.getName();
System.out.println(name1);
//5.getParameterTypes():形参列表
//parameter 参数
Class[] parameterTypes = m.getParameterTypes();
if (!(parameterTypes==null&¶meterTypes.length==0)){
for (Class c : parameterTypes){
System.out.println(c.getName());//如果没有.getName()方法,得到的就是一个类,不是你想要的得到的东西
}
}
//6.getExceptionTypes():抛出的异常
Class[] exceptionTypes = m.getExceptionTypes();
for (Class c: exceptionTypes){
System.out.println(c.getName());
}
}
}
}
获取构造器结构
public class OtherTest {
public static void main(String[] args) throws Exception {
Class clazz = Person.class;
//getConstructors():获取当前运行时类中声明为public的构造器
Constructor[] constructor = clazz.getConstructors();
for (Constructor c: constructor){
System.out.println(c);
}
System.out.println();
//getDeclaredConstructors():获取当前运行时类中声明的所有的构造器
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor c: declaredConstructors){
System.out.println(c);
}
}
}
获取父类,父类的泛型(比较重要)
功能性代码:需要的时候直接复制就可以了
public class OtherTest02 {
public static void main(String[] args) {
Class clazz = Person.class;
//获取运行时类的父类
Class superclass = clazz.getSuperclass();
System.out.println(superclass.getName());
//获取运行时类的带泛型的父类 Generic通用
Type genericSuperclass = clazz.getGenericSuperclass();
System.out.println(genericSuperclass);
//获取运行时类的带泛型的父类的泛型 Parameter参数
//先强转成ParameterizedType
ParameterizedType parameterizedType = (ParameterizedType)genericSuperclass;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();//Actual:实际 Argument:参数
for (Type t : actualTypeArguments){
System.out.println(t.getTypeName());
}
}
}
获取接口(动态代理中会用到)
public class InterfaceTest {
public static void main(String[] args) {
Class clazz = Person.class;
//获取当前运行时类实现的接口
Class[] interfaces = clazz.getInterfaces();
for (Class c : interfaces){
System.out.println(c);
}
System.out.println();
//获取当前运行时类的父类实现的接口
Class superclass = clazz.getSuperclass();
Class[] interfaces1 = superclass.getInterfaces();
}
}
获取包
public class PackageTest {
public static void main(String[] args) {
Class clazz = Person.class;
//获取运行时类所在的包
Package aPackage = clazz.getPackage();
}
}
获取注解
通过反射读取注解的内容,根据内容判定需要做什么后续的操作
public class AnnotationTest {
public static void main(String[] args) {
Class clazz = Person.class;
//获取运行时类声明的注解
Annotation[] annotations = clazz.getAnnotations();
for (Annotation a : annotations){
System.out.println(a);
}
}
}
调用运行时类的指定结构(重点)
这里的指定结构,主要是属性,方法,构造器,重点是方法
获取,设置属性(需要掌握)
/**
* 如何操作运行时类中的属性 需要掌握
*/
public class ReflectionTest {
public static void main(String[] args) throws Exception {
Class clazz = Person.class;
//创建运行时类的对象
Person person = (Person) clazz.newInstance();
//获取指定的属性:要求运行时类中属性声明为public 非静态的属性需要依托于对象才能修改值 所以创建一个对象
//所以通常不采用此方法
//Field id = clazz.getField("id");
//1.getDeclaredField():获取运行时类中指定变量名的属性
Field name = clazz.getDeclaredField("name");
//2.设置当前属性是可访问的
name.setAccessible(true);
/*
设置当前属性的值
set():参数1:指明设置哪个对象的属性 参数2:将此属性值设置为多少
*/
//3.获取,设置指定对象的此属性值
name.set(person, "lbc");
/*
获取当前属性的值
get():参数1:获取哪个对象的当前属性值
*/
name.get(person);
}
}
调用方法(需要掌握)
/**
* 如何操作运行时类中的方法 需要掌握
*/
public class ReflectionTest02 {
public static void main(String[] args) throws Exception {
Class clazz = Person.class;
//创建运行时类的对象
Person person = (Person) clazz.newInstance();
/*
1.获取指定的某个方法
getDeclaredMethod():参数1:指明方法的名称,参数2:指明方法的形参列表
*/
Method show = clazz.getDeclaredMethod("show", String.class);
//2.设置方法可用
show.setAccessible(true);
/*
invoke():参数1:方法调用者,参数2:给方法形参赋值的实参
invoke 调用
invoke()方法的返回值即为对应类中调用的方法的返回值,没有返回值invoke()返回null
*/
show.invoke(person, "CHN");
//调用静态方法
Method showDesc = clazz.getDeclaredMethod("showDesc");
showDesc.setAccessible(true);
//静态方法传类或者null就可以了
//showDesc.invoke(null);
showDesc.invoke(Person.class);
}
}
调用构造器
/**
* 如何操作运行时类中的构造器
*/
public class ReflectionTest03 {
public static void main(String[] args) throws Exception {
Class clazz = Person.class;
/*
1.获取指定的构造器
getDeclaredConstructor():参数:指明构造器的参数列表
*/
Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class);
//2.设置可以访问
declaredConstructor.setAccessible(true);
//3.调用构造器创建运行时类的对象
Person lbc = (Person) declaredConstructor.newInstance("lbc");
System.out.println(lbc);
}
}