目录
1.反射机制
2..反射带来的问题
3.关于java.lang.Class的理解
4.获取Class实例的方式
5.类的加载器
6.使用类的加载器获取配置文件信息的方法
7.创建运行时类的对象:通过反射
8.获取属性结构
9.获取方法
10.获取构造器
11.获取运行时类的父类
12.调用运行类中指定的结构:属性、方法、构造器(重点)
一、调用指定的属性:(掌握)
二、调用指定的方法:(掌握)
三、如何调用运行时类的构造器
13.反射的应用
定义:动态获取运行时类的属性或调用运行时类的方法叫做反射机制
1.体现了动态性,是动态语言的体现
2.动态语言:在运行时代码可以根据某些条件改变自身结构。
1.反射机制与面向对象中的封装性是否矛盾?
因为通过反射能够调用私有的属性、方法、构造器;但是不矛盾;封装性是建议你不要调用私有的,该有的功能都已经公开了;反射只是能够调用私有的,调不调看你自己。
2.开发中使用直接new的方式还是反射?
大部分还是new的方式;用反射时-动态性
1.类的加载过程:程序经过javac.exe后,生成一个或多个字节码文件(.class)。接着使用java.exe对字节码文件进行解释运行,相当于把某个字节码文件加载到内存中。此过程称为类的加载。加载到内存中的类,就称为运行时类,此运行时类,就作为Class的一个实例。
2.Class的实例对应着一个运行时类。
3.加载到内存中的运行时类,会缓存一定的时间,在此时间内,可以获取此运行时类。
4.只要数组的元素类型和维度一样,就是同一个Class
5.Class类的对象可以是加载在内存中的各种对象
1.方式一:调用运行时类的属性:.class
2.通过运行时类的对象,getclass
3.调用Class静态方法:forName(classPath);一般用方式三
4.了解:使用类的加载器,ClassLoader
//获取Class实例的方式
@Test
public void test1() throws Exception {
//1.调用.class
Class clazz1 = Person.class;
System.out.println(clazz1);
//2.通过运行时类的对象
Person p = new Person();
Class clazz2 = p.getClass();
System.out.println(clazz2);
//3.调用Class静态方法:forName(classPath)
Class clazz3 = Class.forName("com.gz.java.utility.Person");
System.out.println(clazz3);
//4.使用类的加载器
ClassLoader classLoader = ClassTest.class.getClassLoader();
Class clazz4 = classLoader.loadClass("com.gz.java.utility.Person");
System.out.println(clazz4);
}
1.作用:将类加载到内存当中。
2.对于自定义类,使用系统类加载器
3.调用系统类加载器的getParent:获取扩展类加载器
4.而引导类加载器只用来加载Java的核心类库,无法加载自定义类
@Test
public void test1() throws IOException {
Properties p = new Properties();
// //1.使用p.load(输入流)
// FileInputStream fis = new FileInputStream("jdbc.properties");
// p.load(fis);
//2.使用ClassLoader
ClassLoader c1 = PropetiesTest.class.getClassLoader();
InputStream is = c1.getResourceAsStream("jdbc1.properties");
p.load(is);
String user = p.getProperty("user");
String psw = p.getProperty("psw");
System.out.println(user + "\t" + psw);
}
1.newInstance():创建运行时类的对象;内部调用了运行时类的空参构造器;
2.只有构造器才能造对象
3.要想此方法能够正常创建运行时类的对象;则运行时类必须提供空参的构造器;且该空参构造器通常设置为public。
4.在Javabean中要求提供一个public的空参构造器:便于通过反射创建运行时类的对象;便于子类继承运行时类,默认调用super()时,不会报错。
//创建运行时类的对象:通过反射
@Test
public void test2() throws IllegalAccessException, InstantiationException {
Class clazz1 = Person.class;
Person p = clazz1.newInstance();
System.out.println(p);
}
1.getFields():获取当前运行时类及其父类中声明为public访问权限的属性
2.getDeclaredFields():获取当前运行时类中声明的所有属性(不包含父类中声明的属性)
3.获取每个属性的具体参数:了解
权限修饰符:getModifiers
数据类型:getType
变量名:getName
1.getMethods(): 获取当前运行时类及其父类中声明为public访问权限的方法
2.getDeclaredMethods(): 获取当前运行时类中声明的所有方法(不包含父类中声明的方法)
3.获取每个方法具体参数:了解
方法注解:getAnnotations(生命周期为Runtime才能获取到)
权限修饰符:getModifiers
返回值类型:get ReturnType
方法名:getName
形参列表:getParameterTypes
抛出的异常:getExceptionTypes
1.getConstructors:获取当前运行时类及其父类中声明为public访问权限的构造器
2.getDeclaredConstructors:获取当前运行时类中声明的所有构造器(不包含父类中声明的构造器)
1.getSuperClass()
2.getGenericSuperClass():带泛型父类
3.获取带泛型父类的泛型
4.获取运行时类的接口
5.获取运行时类的包:get Package()
6.获取运行时类的注解:getAnnotations
//使用反射获取运行时类的父类、带泛型的父类、父类的泛型的泛型、类的接口、父类的接口、类的包、注解
@Test
public void test4(){
Class clazz = Person.class;
//使用反射获取运行时类的父类
System.out.println(clazz.getSuperclass());
//使用反射获取运行时类带泛型父类
System.out.println(clazz.getGenericSuperclass());
//使用反射获取运行时类带泛型父类的泛型
Type genericSuperclass = clazz.getGenericSuperclass();
ParameterizedType param = (ParameterizedType) genericSuperclass;
Type[] actualTypeArguments = param.getActualTypeArguments();
System.out.println(((Class)actualTypeArguments[0]).getName());
//使用反射获取运行时类的接口
Class[] interfaces = clazz.getInterfaces();
for (Class c : interfaces){
System.out.println(c);
}
//使用反射获取运行时类的父类的接口
Class[] interfaces1 = clazz.getSuperclass().getInterfaces();
for (Class c : interfaces1){
System.out.println(c);
}
//使用反射获取运行时类的包
Package p = clazz.getPackage();
System.out.println(p);
//使用反射获取运行时类的方法的注解
Method[] methods = clazz.getMethods();
for (Method m : methods) {
Annotation[] annotations = m.getAnnotations();
for (Annotation a : annotations) {
System.out.println(a);
}
}
}
1.创建运行时类实例,创建运行时类的对象
2.getDeclaredField(String Name):获取当前运行时类中指定变量的属性;
3.setAccessible(true):保证该属性可以被访问(即使封装为private也可以)
4.set(p,fieldName):设置指定对象的变量
5.get(p):获取指定对象的指定变量
1.创建运行时类实例,创建运行时类的对象
2. getDeclaredMethod(): 参数一:指明获取方法的名称;参数二:指明获取方法的形参列表
3.setAccessible(true);设置为可以访问的
4.invoke(p,实参):参数一:方法的调用者;参数二:给方法形参赋值的形参
注意:invoke()方法的返回值即为对应类中调用方法的返回值。若为void没有返回值,则返回null
5.如何调用静态方法
一样的步骤,invoke里面写上当前运行时类
1.找到指定构造器
2.setAccessible():保证次构造器可访问
3..newInstance():调用该构造器造对象
1.静态代理:代理类和被代理类在编译期间,就确定下来了
2.动态代理与AOP
具体见:
Java-代理模式_perseveregz的博客-CSDN博客