程序员学习 java语言反射

本文详细介绍了Java中类的加载过程,包括加载、连接和初始化三个阶段,并深入探讨了不同类型的类加载器及其作用。此外,还全面解析了Java反射机制的工作原理,包括获取Class对象的不同方式、反射API的使用方法以及如何利用反射创建对象实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

                     

类的加载

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
加载 
就是指将class文件读入内存,并为之创建一个Class对象。
任何类被使用时系统都会建立一个Class对象。
连接
验证 是否有正确的内部结构,并和其他类协调一致
准备 负责为类的静态成员分配内存,并设置默认初始化值
解析 将类的二进制数据中的符号引用替换为直接引用

类的初始化时机:
创建类的实例
类的静态变量,或者为静态变量赋值
类的静态方法
使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
初始化某个类的子类
直接使用java.exe命令来运行某个主类

类加载器


负责将.class文件加载到内在中,并为之生成对应的Class对象。
虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。
类加载器的组成
Bootstrap ClassLoader 根类加载器
Extension ClassLoader 扩展类加载器
Sysetm ClassLoader 系统类加载器

类加载器的作用

Bootstrap ClassLoader 根类加载器
也被称为引导类加载器,负责Java核心类的加载
比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
Extension ClassLoader 扩展类加载器
负责JRE的扩展目录中jar包的加载。
在JDK中JRE的lib目录下ext目录
Sysetm ClassLoader 系统类加载器
负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径

反射:

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对

 

于任意一个对象,都能够调用他的任意一个方法和属性,这种动态获取的信息以及动态调用

 

对象的方法的功能成为java语言的反射机制。要想解剖一个类,必须要获取到这个类的字

 

节码文件对象而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应

 

的Class类型的对象

 

获取Class对象的三种方式

加载XX.class文件进内存时就被封装成了对象,该对象就是字节码文件对象。如何获取Class对象呢?

方式一:

 通过对象的getClass方法进行获取。

如:Class clazz=new Person().getClass();//Person是一个类名

 麻烦之处:每次都需要具体的类和该类的对象,以及调用getClass方法。

方式二:

任何数据类型都具备着一个静态的属性class,这个属性直接获取到该类型的对应Class对象。

 如:Class clazz=Person.class;//Person是一个类名

 比第一种较为简单,不用创建对象,不用调用getClass方法,但是还是要使用具体的类,和该类中的一个静态属性class完成。

方式三:

 这种方式较为简单,只要知道类的名称即可。不需要使用该类,也不需要去调用具体的属性和行为。就可以获取到Class对象了。

 如:Class clazz=Class.forName("包名.Person");//Person是一个类名

 这种方式仅知道类名就可以获取到该类字节码对象的方式,更有利于扩展。

注:

九个预定义的Class:

 1)包括八种基本类型(byte、short、int、long、float、double、char、boolean)的字节码对象和一种返回值为void类型的void.class。

2)Integer.TYPE是Integer类的一个常量,它代表此包装类型包装的基本类型的字节码,所以和int.class是相等的。基本数据类型的字节码都可以用与之对应的包装类中的TYPE常量表示

 、Class类中的方法

 static Class forName(String className)

返回与给定字符串名的类或接口的相关联的Class对象。

 Class getClass()

返回的是Object运行时的类,即返回Class对象即字节码对象

Constructor getConstructor()

返回Constructor对象,它反映此Class对象所表示的类的指定公共构造方法。

Field getField(String name)

 返回一个Field对象,它表示此Class对象所代表的类或接口的指定公共成员字段。

Field[] getFields()

 返回包含某些Field对象的数组,表示所代表类中的成员字段。

Method getMethod(String name,Class…?parameterTypes)

 返回一个Method对象,它表示的是此Class对象所代表的类的指定公共成员方法。

Method[] getMehtods()

返回一个包含某些Method对象的数组,是所代表的的类中的公共成员方法。

String getName()

 以String形式返回此Class对象所表示的实体名称。

String?getSuperclass()

 返回此Class所表示的类的超类的名称

boolean isArray()

 判定此Class对象是否表示一个数组

boolean isPrimitive()

判断指定的Class对象是否是一个基本类型。

T newInstance()

创建此Class对象所表示的类的一个新实例。

 

通过方法获取类实例对象。之前我们用的已知类,创建对象的做法:

1)查找并加载XX.class文件进内存,并将该文件封装成Class对象。

2)再依据Class对象创建该类具体的实例。

 3)调用构造函数对对象进行初始化。

 如:Person p=new Person();

?现在用Class对象来获取类实例对象的做法:

 1)查找并加载指定名字的字节码文件进内存,并被封装成Class对象。

2)通过Class对象的newInstance方法创建该Class对应的类实例

 3)调用newInstance()方法会去使用该类的空参数构造函数进行初始化。

如:

String className="包名.Person";

 Class clazz=Class.forName(className);

Object obj=clazz.newInstance();

//事例

package Reflect;

 

public class Person {

private String name;

private int 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;

}

public Person() {

super();

// TODO Auto-generated constructor stub

}

public Person(String name, int age) {

super();

this.name = name;

this.age = age;

}

 

}

 

package Reflect;

 

import cn.itcast.Person;

 

public class ReflectDemo {

public static void main(String[] args) throws Exception {

String className = "cn.itcast.Person";

Class clazz = Class.forName(className);

Person p = (Person) clazz.newInstance();

 

}

}

 

 

 

// 获取字节码文件对象

Class c = Class.forName("cn.itcast.Person");

 

 获取构造方法

public Constructor[] getConstructors():所有公共构造方法

 public Constructor[] getDeclaredConstructors():所有构造方法(私有公有的构造方法);

构造方法的遍历:

Constructor[] cons = c.getDeclaredConstructors();

 for (Constructor con : cons) {

System.out.println(con);

 }

 

 获取单个构造方法

 

参数表示的是:你要获取的构造方法的构造参数个数及数据类型的class字节码文件对象

Constructor con = c.getConstructor();// 返回的是构造方法对象

// 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

Object obj = con.newInstance();

System.out.println(obj);

 

/*

 * 需求:通过反射去获取该构造方法并使用:

 * public Person(String name, int age)

 * 

 * Person p = new Person("张三",20);

 * System.out.println(p);

 */

public class ReflectDemo2 {

public static void main(String[] args) throws Exception {

// 获取字节码文件对象

Class c = Class.forName("cn.itcast_01.Person");

 

// 获取带参构造方法对象

Constructor con = c.getConstructor(String.class, int.class,

String.class);

 

// 通过带参构造方法对象创建对象

// public T newInstance(Object... initargs)

Object obj = con.newInstance("张三", 27);

System.out.println(obj);

}

}

 

/*

 * 需求:通过反射获取私有构造方法并使用

 * private Person(String name){}

 * 

 * Person p = new Person("张三");

 * System.out.println(p);

 */

public class ReflectDemo3 {

public static void main(String[] args) throws Exception {

// 获取字节码文件对象

Class c = Class.forName("cn.itcast_01.Person");

 

// 获取私有构造方法对象

Constructor con = c.getDeclaredConstructor(String.class);

 

// 用该私有构造方法创建对象

// 暴力访问

con.setAccessible(true);// 值为true则指示反射的对象在使用时应该取消Java语言访问检查。

Object obj = con.newInstance("张三");

 

System.out.println(obj);

}

}

Field类

1、Field类代表某个类中一个成员变量

2、方法

Field getField(String s);//只能获取公有和父类中公有

Field getDeclaredField(String s);//获取该类中任意成员变量,包括私有

setAccessible(ture);

//如果是私有字段,要先将该私有字段进行取消权限检查的能力。也称暴力访问。

set(Object obj, Object value);//将指定对象变量上此Field对象表示的字段设置为指定的新值。

Object get(Object obj);//返回指定对象上Field表示的字段的值。

 

事例:

假如将上述Person类的name和设成私有的

 

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

 

/*

 * 通过发生获取成员变量并使用

 */

public class ReflectDemo {

public static void main(String[] args) throws Exception {

// 获取字节码文件对象

Class c = Class.forName("cn.itcast_01.Person");

 

/*

 * Person p = new Person(); p.address = "北京"; System.out.println(p);

 */

 

// 通过无参构造方法创建对象

Constructor con = c.getConstructor();

Object obj = con.newInstance();

System.out.println(obj);

 

// 获取单个的成员变量

// 获取name并对其赋值

// NoSuchFieldException

Field nameField = c.getDeclaredField("name");

// IllegalAccessException

nameField.setAccessible(true);

nameField.set(obj, "李四");

System.out.println(obj);

 

// 获取age并对其赋值

Field ageField = c.getField("age");

ageField.setAccessible(true);

ageField.set(obj, 27);

System.out.println(obj);

}

}

j

动态代理    

  代理:本来应该自己做的事情,却请了别人来做,被请的人就是代理对象。
举例:春季回家买票让人代买
动态代理:在程序运行过程中产生的这个对象
而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理

在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib
Proxy类中的方法创建动态代理类对象
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
最终会调用InvocationHandler的方法
InvocationHandler
Object invoke(Object proxy,Method method,Object[] args)

举例:


用动态代理实现管理员和学生的功能权限问题
public interface StudentDao {
public abstract void login();


public abstract void regist();
}

public class StudentDaoImpl implements StudentDao {


@Override
public void login() {
System.out.println("登录功能");
}


@Override
public void regist() {
System.out.println("注册功能");
}


}



/*
 * 用户操作接口
 */
public interface UserDao {
public abstract void add();


public abstract void delete();


public abstract void update();


public abstract void find();

public class UserDaoImpl implements UserDao {


@Override
public void add() {
System.out.println("添加功能");
}


@Override
public void delete() {
System.out.println("删除功能");
}


@Override
public void update() {
System.out.println("修改功能");
}


@Override
public void find() {
System.out.println("查找功能");
}}

                 import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;


public class MyInvocationHandler implements InvocationHandler {
private Object target; // 目标对象


public MyInvocationHandler(Object target) {
this.target = target;
}


@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("权限校验");
Object result = method.invoke(target, args);
System.out.println("日志记录");
return result; // 返回的是代理对象
}
}

import java.lang.reflect.Proxy;


public class Test {
public static void main(String[] args) {
UserDao ud = new UserDaoImpl();
ud.add();
ud.delete();
ud.update();
ud.find();
System.out.println("-----------");
// 我们要创建一个动态代理对象
// Proxy类中有一个方法可以创建动态代理对象
// public static Object newProxyInstance(ClassLoader loader,Class<?>[]
// interfaces,InvocationHandler h)
// 我准备对ud对象做一个代理对象
MyInvocationHandler handler = new MyInvocationHandler(ud);
UserDao proxy = (UserDao) Proxy.newProxyInstance(ud.getClass()
.getClassLoader(), ud.getClass().getInterfaces(), handler);
proxy.add();
proxy.delete();
proxy.update();
proxy.fi

          

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值