反射
- 什么是Java的动态机制
- 什么是反射机制
- 什么是Class类
- Class提供了诸多的get方法
- 反射机制实例化对象
- Class提供了一个方法
- Constructor类
- 指定构造器实例化对象
- Method类
- 获取一个类中的所有方法
- Class类提供了对应的方法
- 获取本类自定义的所有方法
- Class类提供了对应的方法
- 获取表示的方法中的相关信息
- Class类提供了对应的方法
- 利用反射机制调用方法
- Class类提供了对应的方法
- 暴力反射
- 反射机制访问类的私有成员的方法
- 反射机制操作属性
- Class类提供了对应的方法
- 通过类对象获取类加载路径和当前类路径
- Class类提供了对应的方法
什么是Java的动态机制
什么是反射机制
反射是java的动态机制,允许程序在[运行期间]再确定对象实例化,方法调用,属性操作等
反射可以提高代码的灵活度和可扩展性,但是运行效率较慢,开销较大,避免过度使用
什么是Class类
- java.lang.Class类是Java反射机制的基础
- Class的每一个实例用于表示JVM中加载的一个类
- JVM中每个被加载的类都有且只有一个Class的实例
- Class类的构造器是私有的,开发者不能主动实例化Class类的对象
- Class类的对象仅能由JVM创建
类对象:
Class类的实例
-
JVM加载一个类的字节码文件同时会实例化一个Class的实例用来记录加载的类的信息.
那么这个Class的实例就可以反映出加载的类的相关信息(类名,包信息,构造器,方法,属性等)
从而在程序运行期间供我们了解一个类的内容以便进行操作. -
在JVM内部,每个被加载的类都有且只有一个Class的实例.
-
反射的第一步是获取一个类的类对象(Class的实例)
获取方式一:
- 类名.class
例如:
Class c1 = String.class;//获取String的类对象
Class c2 = int.class;//获取int(基本类型)的类对象.
注意:基本类型获取类对象只有这一种方式
获取方式二:
- Class.forName(String className)
通过指定一个类的完全限定名来获取一个类的类对象
例如:
Class c1 = Class.forName(“java.lang.String”);
Class c2 = Class.forName(“java.util.ArrayList”);
Class提供了诸多的get方法
用于获取其表示的类的相关信息
- getName()
- getSimpleName()
- getPackage()
- getPackage().getName()
反射机制实例化对象
Class提供了一个方法
- Object newInstance()
类必须有一个无参数的构造器,否则就需要传入构造器对应的参数
类的构造器的访问权限需要足够,通常设置为public
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
Person person = new Person();
System.out.println(person);
Class cls = Class.forName("reflect.Person");
System.out.println(cls.newInstance());
Scanner scanner = new Scanner(System.in);
System.out.println("请输入类名");
Class clsName = Class.forName(scanner.nextLine());
System.out.println(clsName.newInstance());
}
Constructor类
- Constructor类是反射对象之一,它的每一个实例用于表示一个构造器
- 使用无参构造器,等效与Class中的newInstance()
如果构造器抛出特定异常此方式可对应抛出该异常
指定构造器实例化对象
public class Person {
private String name = "张三";
private int age = 22;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public static void main(String[] args) throws InvocationTargetException,
InstantiationException, IllegalAccessException, NoSuchMethodException,
ClassNotFoundException {
Person person = new Person("李四",22);
System.out.println(person);
Class cls = Class.forName("reflect.Person");
Constructor constructor = cls.getConstructor(String.class,int.class);
System.out.println(constructor.newInstance("王五",36));
Constructor constructor1 = cls.getConstructor();
System.out.println(constructor1.newInstance());
}
Method类
Method类是反射对象之一,它的每一个实例用于表示一个方法
通过Method对象我们可以得知该方法的相关信息(方法名,参数列表,返回值,访问修饰符等)
还可以通过Method对象调用该方法
获取一个类中的所有方法
Class类提供了对应的方法
- Method[] getMethods()
public class Person {
private String name = "张三";
private int age = 22;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public void sayHello(){
System.out.println();
}
public void sayHi(){
System.out.println();
}
public void doSome(){
System.out.println();
}
public void sleep(){
System.out.println();
}
public void watchTV(){
System.out.println();
}
public void study(){
System.out.println();
}
public void playGame(){
System.out.println();
}
public void sing(){
System.out.println();
}
public void say(String info){
System.out.println(name+":"+info);
}
public void say(String info,int count){
for (int i=0;i<count;i++){
System.out.println(name+":"+info);
}
}
private void hehe(){
System.out.println("我是Person的私有方法hehe!!");
}
}
public static void main(String[] args) throws ClassNotFoundException {
Scanner scanner = new Scanner(System.in);
Class cls = Class.forName(scanner.nextLine());
Method[] methods = cls.getMethods();
System.out.println("一共:" +methods.length+ "个方法");
for(Method method : methods){
System.out.println(method.getName());
}
}
获取本类自定义的所有方法
Class类提供了对应的方法
- Method[] getDeclaredMethods()
不含超类继承的方法
public static void main(String[] args) throws ClassNotFoundException {
Class cls = Class.forName("reflect.Person");
Method[] methods = cls.getDeclaredMethods();
for(Method method : methods){
System.out.println(method.getName());
}
}
获取表示的方法中的相关信息
Class类提供了对应的方法
- getDeclaredMethod(String)
- getDeclaredMethod(String, in)
获取有参方法时,getDeclaredMethod的第一个参数为方法名,从第二个参数开始为获取方法的参数列表 - getParameterCount()
获取当前方法的参数个数 - getModifiers()
获取当前方法的访问修饰符
Method对象表示一个方法,其提供了一组可以获取表示的方法中的相关信息
public static void main(String[] args) throws NoSuchMethodException,
ClassNotFoundException {
Class cls = Class.forName("reflect.Person");
Method method = cls.getDeclaredMethod("say", String.class, int.class);
System.out.println("方法名" +method.getName());
System.out.println("参数个数" +method.getParameterCount());
switch (method.getModifiers()){
case Modifier.PUBLIC:
System.out.println("是一个公开方法");
break;
case Modifier.PRIVATE:
System.out.println("是一个私有方法");
break;
case Modifier.PROTECTED:
System.out.println("是一个受保护方法");
}
}
利用反射机制调用方法
Class类提供了对应的方法
- Object invoke(Object obj)
无参调用
public static void main(String[] args) throws NoSuchMethodException,
ClassNotFoundException, InstantiationException, IllegalAccessException,
InvocationTargetException {
Class cls = Class.forName("reflect.Person");
Object obj = cls.newInstance();
Method method = cls.getDeclaredMethod("doSome");
method.invoke(obj);
}
- Object invoke(Object obj, Object…… args)
确保传递给invoke方法的参数列表与所调用的方法的参数列表相匹配
否则,将会抛出异常
public static void main(String[] args) throws Exception {
Class cls = Class.forName("reflect.Person");
Object obj = cls.newInstance();
Method method = cls.getDeclaredMethod("say",String.class);
method.invoke(obj, "hello");
Method method1 = cls.getDeclaredMethod("say",String.class,int.class);
method1.invoke(obj, "大家好",5);
}
暴力反射
反射机制访问类的私有成员的方法
- setAccessible(true)
强行打开访问权限,访问私有方法 - setAccessible(false)
使用后,关闭私有成员的访问权限
public static void main(String[] args) throws Exception {
Class cls = Class.forName("reflect.Person");
Method method = cls.getDeclaredMethod("hehe");
method.setAccessible(true);
method.invoke(cls.newInstance());
method.setAccessible(false);
}
反射机制操作属性
Class类提供了对应的方法
- Field getDeclaredField(String name)
允许访问类的声明字段
返回一个Field对象,表示指定类或接口声明的指定公共、受保护、默认(包)访问或私有字段 - void set(Object obj, Object value)
Field类的一个方法,obj是包含该字段的对象,value是要设置的新值 - native Object get(Object obj)
public class Teacher {
public String name;
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
'}';
}
}
public static void main(String[] args) throws ClassNotFoundException,
InstantiationException, IllegalAccessException, NoSuchFieldException {
Class cls = Class.forName("reflect.Teacher");
Object object = cls.newInstance();
cls.getDeclaredField("name").set(object, "Bloom");
System.out.println(object);
}
通过类对象获取类加载路径和当前类路径
Class类提供了对应的方法
- getClassLoader()
返回该类的类加载器,它是用来加载类文件的对象 - getResource(“.”)
获取资源路径的方法,它从当前类的类加载器中查找资源
"."代表当前目录,这表示获取当前目录下的所有资源 - toURI()
将路径转换为统一资源标识符(URI),它可以唯一地识别任何资源,包括网络资源、文件系统资源等
public class ReflectDemo {
public static void main(String[] args) throws URISyntaxException {
File baseDir = new File(
//获取当前类的类加载器中的当前目录的资源路径,并将其转换为URI
ReflectDemo.class.getClassLoader().getResource(".").toURI()
);
System.out.println(baseDir);
File dir = new File(
//获取当前类的类加载器中的当前目录的资源路径,并将其转换为URI
ReflectDemo.class.getResource(".").toURI()
);
System.out.println(dir);
}
}