类的加载
- 概述:当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现类的初始化
- 加载时机:
(1)创建类对象时
(2)访问类的静态变量或调用类的静态方法
(3)通过反射来创建类对象
(4)初始化某个类的子类
(5)通过java.exe命令运行某个类
类加载器
- 概述:将.class文件加载到内存中,并生成对应的.class对象
- 分类及其作用:
反射
- 概述:就是在运行状态中的一种动态调用类的方法或者属性的一种机制,即获取字节码文件对象,然后刨析类中的成员变量,构造方法,成员方法
- 获取class文件对象的三种方式
(1)Object类的getClass()方法
(2)静态属性class
(3)class类中静态方法forName()
package org.westos2.demo2;
public class MyTest {
public static void main(String[] args) throws ClassNotFoundException {
//通过getClass方法获取字节码对象
Student student = new Student();
Class aClass1 = student.getClass();
Class aClass2 = student.getClass();
System.out.println(aClass1==aClass2);
//通过类的静态属性class获取字节码对象
Class aClass = Student.class;
System.out.println(aClass==aClass1);
//通过Class中的forName方法获取字节码对象
//参数需要传入类的全限定名:包名+类名
Class aClass3 = Class.forName("org.westos2.demo2.Student");
System.out.println(aClass3==aClass2);
}
}
结果表明,代码中的几个对象都是同一个对象,因为一个类只有一个.class文件
一个类的由三部分构成:构造方法(ConStructor)、成员变量(Field)、成员方法(Method)
下面通过反射来刨析类的构成:
- 获取构造方法(空参构造,有参构造,私有构造)
package org.westos2.demo2;
public class Student {
//空参构造
public Student() {
System.out.println("执行空参构造");
}
//有参构造
public Student(String name) {
System.out.println("执行有参构造");
}
//私有构造
private Student(String name,int age) {
System.out.println("执行私有构造");
}
}
package org.westos2.demo2;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class MyTest {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取字节码对象
Class aClass = Student.class;
//通过getConstructors方法获取所有构造方法对象,私有的除外
Constructor[] constructors = aClass.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("-------------------------------");
//通过getDeclaredConstructors方法获取所有构造方法对象,包括私有
Constructor[] declaredConstructors = aClass.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
System.out.println("-------------------------------");
//通过getConstructor获取空参构造对象
//并通过newInstance创建一个该类实例
Constructor constructor = aClass.getConstructor();
Student student = (Student) constructor.newInstance();
System.out.println(student);
//通过getConstructor,传入参数的class类型,获取空参构造对象,不能获取私有的
//并通过newInstance创建一个该类实例
Constructor constructor1 = aClass.getConstructor(String.class);
Student student1 = (Student) constructor1.newInstance("张三");
System.out.println(student1);
//通过getDeclaredConstructor获取私有构造对象
//通过setAccessible取消语法检测
//并通过newInstance创建一个该类实例
Constructor declaredConstructor = aClass.getDeclaredConstructor(String.class, int.class);
declaredConstructor.setAccessible(true);
Object o = declaredConstructor.newInstance("张三", 23);
System.out.println(o);
}
}
- 获取成员变量(公共成员变量,私有成员变量)
package org.westos2.demo3;
public class Student {
//成员变量
public String name;
//私有成员变量
private int age;
}
package org.westos2.demo3;
import java.lang.reflect.Field;
public class MyTest {
public static void main(String[] args) throws Exception {
//获取字节码对象
Class aClass = Class.forName("org.westos2.demo3.Student");
//通过getFields方法获取类中所有字段对象,私有的除外
Field[] fields = aClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("-------------------------------");
//通过getDeclaredFields方法获取类中所有字段对象,包括私有
Field[] declaredFields = aClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
System.out.println("-------------------------------");
//通过getField方法获取单个字段对象,不适合私有
Field name = aClass.getField("name");
//获取构造方法对象
Object o = aClass.getConstructor().newInstance();
//给字段赋值
name.set(o,"张三");
//获取字段值
Object o1 = name.get(o);
System.out.println(o1);
//通过getDeclaredField方法获取私有单个字段对象
Field age = aClass.getDeclaredField("age");
//取消私有语法检测
age.setAccessible(true);
//给私有字段赋值
age.set(o,23);
//获取私有字段的值
Object o2 = age.get(o);
System.out.println(o2);
}
}
- 获取成员方法(无参无返回值、有参带返回值、私有方法)
package org.westos2.demo4;
public class Student {
//无参无返回值成员方法
public void method1(){
System.out.println("这是一个无参无返回值成员方法");
}
//有参带返回值成员方法
public int method2(String name){
System.out.println("这是一个有参带返回值成员方法");
return 18;
}
//私有方法
private int method(String name,int num){
System.out.println("这是一个私有方法");
return 18+num;
}
}
package org.westos2.demo4;
import java.lang.reflect.Method;
public class MyTest {
public static void main(String[] args) throws Exception {
//获取字节码对象
Class aClass = Student.class;
//通过getMethods方法获取所有方法对象,包括父类的,不包括私有
Method[] methods = aClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("----------------------------------");
//通过getDeclaredMethods获取该类所有方法对象,包括私有
Method[] declaredMethods = aClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
System.out.println("----------------------------------");
//通过getMethod获取单个方法对象,参数1代表方法名称,参数2代表方法参数的字节码类型
Method method1 = aClass.getMethod("method1");
System.out.println(method1);
//让空参方法执行
//获取构造方法实例
Object o = aClass.getConstructor().newInstance();
//通过invoke让方法执行
Object invoke = method1.invoke(o);
System.out.println(invoke);
System.out.println("----------------------------------");
//获取有参方法对象
Method method2 = aClass.getMethod("method2", String.class);
System.out.println(method2);
//让有参方法执行
Object invoke1 = method2.invoke(o, "张三");
System.out.println(invoke1);
System.out.println("----------------------------------");
//获取私有方法对象
Method method = aClass.getDeclaredMethod("method", String.class, int.class);
System.out.println(method);
//让私有方法执行
//取消语法检测
method.setAccessible(true);
Object invoke2 = method.invoke(o, "李四", 24);
System.out.println(invoke2);
}
}
动态代理
- 概述:是一种设计模式,可以在不修改源代码的情况下,对功能进程增强,使用前提是要有接口,否则无法进行动态代理;在程序运行期间,通过反射生成代理对象
- 代理类:Proxy
static Object newProxyInstance (ClassLoader loader, Class < ?>[]interfaces, InvocationHandler h):返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序
package org.westos2.demo5;
public interface User {
//添加用户
void insert();
}
package org.westos2.demo5;
public class UserImpl implements User{
@Override
public void insert() {
System.out.println("添加用户");
}
}
package org.westos2.demo5;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyUtils {
public static User getProxy(User user){
User o = (User) Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), new InvocationHandler() {
Object invoke = null;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//目标对象的方法一执行,这个invoke方法就会执行
if (method.getName().equals("insert")) {
System.out.println("增加的功能1");
invoke = method.invoke(user);
System.out.println("增加的功能2");
}
return invoke;
}
});
return o;
}
}
package org.westos2.demo5;
public class MyTest {
public static void main(String[] args) {
UserImpl user = new UserImpl();
//获取代理对象
User proxy = ProxyUtils.getProxy(user);
proxy.insert();
}
}
动态代理是反射的一种应用,可以根据个人需求不断增强功能,对代码的扩展很实用