反射
反射,从字面意思的理解就是反过来映射,它的功能也是如此,一般我们要在程序的运行过程中获取一个类的内部信息,那么得先生成一个这个类的对象,然后再使用这个类对外提供的方法来获取,这个类对外提供了什么样方法我们就只能获得到什么信息。
在程序的过程中我们无法像直接翻看源代码一样查看到某个类的信息,但是通过反射机制,能让我们在程序运行阶段就能直接获取某个类中的所有信息,就算这个类的信息有些不对外开发,但是我们依然能获取到。
Class类
class类是一个特殊的类,Class类表示正在运行的Java应用程序中的类和接口。
一个类在被JVM加载后,会在内存中生成对应Class对象,而我们可以通过获取对应类的Class对象,来获取这个类的信息。
获取方式
Class类对象只有三种可以获取方式,因为Class中的构造方法被private修饰了,所以我们无法通过构造方法来创建Class类的对象
1、Class.forName(“全类名”)
通过这个静态方法我们可以获取某个类的Class对象,全类名指的是这个类在什么位置
例如:创建test包下的student类的Class对象。
public class demo_1 {
public static void main(String[] args) throws ClassNotFoundException {
Class claz = Class.forName("test.student");
}
}
2、类名.class
Class studentClass = student.class;
3、对象.getClass()
Object类是所有类的父类,在Object类中有一个方法:getClass方法,这个方法可以获取一个对应的Class对象。所以我们可以使用这个方法获取。
常用功能
Class类提供了很多的方法供我们使用,总得来说常用功能可以分为三大类:
- 访问构造方法
- 访问成员变量
- 访问成员方法
针对不同的需求可以使用不同的方法。
1、访问构造方法
访问构造方法是用Constructor类来进行的。
获取构造方法的常用方法
Constructor[] getConstructors():获取所有公共(public)构造方法。
Constructor[] getDeclaredConstructors():获取所有声明的构造方法,包括公共和非公共的。
Constructor getConstructor(Class<?>… parameterTypes):获取具有指定参数类型的公共构造方法。
Constructor getDeclaredConstructor(Class<?>… parameterTypes):获取具有指定参数类型的声明的构造方法,包括公共和非公共的。
需要注意的是,如果获取指定的构造方法,那么需要根据该构造方法来进行传参。
示例
首先创建一个student进行示例说明,该类中拥有两个属性与多个构造方法,分别使用不同的权限修饰符进行修饰。
public final class student {
public String name;
public int age;
public student(){}
private student(String name){
this.name=name;
}
protected student(int age){
this.age=age;
}
public student(String name, int age) {
this.name = name;
this.age = age;
}
}
然后我们使用不同的获取方法进行获取这个类的构造方法。
package test;
import java.lang.reflect.Constructor;
public class demo_1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
Class claz = Class.forName("test.student"); //获取Class对象
Constructor con = claz.getConstructor(); //获取单个的公共构造方法
Constructor[] cons = claz.getConstructors(); // 获取所有公共的构造方法
Constructor[] pcons = claz.getDeclaredConstructors(); //获取所有的构造方法
Constructor targteCon = claz.getDeclaredConstructor(String.class); // 获取指定形参的构造方法
System.out.println("单个的公共构造方法:");
System.out.println(con);
System.out.println("----------------------------------------");
System.out.println("所有公共的构造方法:");
for (Constructor constructor : cons) {
System.out.println(constructor);
}
System.out.println("----------------------------------------");
System.out.println("获取所有的构造方法");
for (Constructor pcon : pcons) {
System.out.println(pcon);
}
System.out.println("----------------------------------------");
System.out.println("获取指定的构造方法");
System.out.println(targteCon);
}
}
运行结果:
2、访问成员变量
访问成员变量是使用Field类来进行的。
获取成员变量的常用方法:
Field getField(Object obj):获取指定对象的成员变量。
Field[] getFields():获取该类的所有公共(public)成员变量。
Field[] getDeclaredFields():获取该类的所有成员变量,包括公共和非公共的。
Field getDeclaredField(String name):获取具有指定名称的成员变量,包括公共和非公共的。
FIeld类中常用方法
对获取出来的成员变量进行操作的话,需要使用Field类,以下是常用的方法,具体详见Java1.8api文档。
示例
首先创建一个studen类用于演示。
package test;
public final class student {
private String name;
public int age;
public student(){}
private student(String name){
this.name=name;
}
protected student(int age){
this.age=age;
}
public student(String name, int age) {
this.name = name;
this.age = age;
}
}
获取成员变量
package test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class demo_1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException {
Class claz = Class.forName("test.student"); //获取Class对象
Field age = claz.getField("age"); //获取指定变量名的公共成员变量
Field[] fields = claz.getFields(); //获取所有公共的成员变量
Field name = claz.getDeclaredField("name");//获取指定变量的成员变量(可获取被private修饰的)
Field[] pfields = claz.getDeclaredFields(); // 获取所有的成员变量
// 下列仅获取成员变量名
System.out.println("获取指定成员变量");
System.out.println(age.getName());
System.out.println("-----------------------------");
System.out.println("获取所有公共的成员变量");
for (Field field : fields) {
System.out.println(field.getName());
}
System.out.println("-----------------------------");
System.out.println("获取指定的成员变量(可获取私有的)");
System.out.println(name.getName());
System.out.println("-----------------------------");
System.out.println("获取所有的成员变量");
for (Field pfield : pfields) {
System.out.println(pfield.getName());
}
System.out.println("-----------------------------");
}
}
运行结果:
3、访问成员方法
访问某个类的成员方法是使用Method对象来进行操作的。
常用的方法有下图所示,具体详见Java1.8Api文档
获取Method对象常用的方法有:
Method[] getMethods():获取所有公共(public)成员方法,包括从Object类继承的方法。
Method[] getDeclaredMethods():获取所有声明的成员方法,不包括从父类继承的方法。
Method getMethod(String name, Class<?>… parameterTypes):获取具有指定名称和参数类型的公共成员方法。
Method getDeclaredMethod(String name, Class<?>… parameterTypes):获取具有指定名称和参数类型的声明的成员方法。
示例:
给student类创建几个成员方法用于演示
package test;
public final class student {
private String name;
public 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 student(){}
private student(String name){
this.name=name;
}
protected student(int age){
this.age=age;
}
public student(String name, int age) {
this.name = name;
this.age = age;
}
private void show(){
System.out.println("芜湖");
}
}
获取成员方法
需要注意的是,如果使用getMethods方法来获取成员方法,那么它会返回本类的公共成员方法,也会返回从父类继承的成员方法。而使用getDeclaredMethods方法来获取的话,那么就不会返回父类的方法
package test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class demo_1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException {
Class claz=Class.forName("test.student");
Method[] ms = claz.getMethods(); //获取所有公共的成员方法(包括从父类继承的方法)
Method getAge = claz.getMethod("getAge"); // 获取指定名称与形参的公共方法,无形参则省略
Method[] pms = claz.getDeclaredMethods(); //获取所有成员方法,不包括从父类继承的方法
Method show = claz.getDeclaredMethod("show"); // 获取指定名称与形参的方法(包括私有化的)
System.out.println("取所有公共的成员方法(包括从父类继承的方法)");
for (Method m : ms) {
System.out.println(m); // 获取方法名称
}
System.out.println("------------------------------------------------");
System.out.println("获取指定名称与形参的公共方法,无形参则省略");
System.out.println(getAge);
System.out.println("------------------------------------------------");
System.out.println("获取所有的成员方法,不包括从父类继承的");
for (Method pm : pms) {
System.out.println(pm);
}
System.out.println("------------------------------------------------");
System.out.println("获取指定名称与形参的方法(包括私有化的)");
System.out.println(show);
}
}
执行结果
注解
在Java中,注解(Annotation)是一种特殊的注释,它提供了一种元数据机制,可以用于描述代码中的信息和元数据。注解是Java 5.0引入的一个新特性,它提供了一种将信息嵌入到Java代码中的方法,并且可以在编译时、运行时和代码生成时使用。
注解的作用域可以是类、方法、变量、参数等。例如,可以使用注解标记类、方法、变量等。
注解可以具有参数,参数可以是常量、字符串、整数等类型。例如:
@MyAnnotation(name="example", value=123)。
注解可以被继承,子类可以继承父类中的注解。
语法:
注解的基本语法很简单,它使用 @符号来标识,后面跟着注解的名称和参数。例如:
@Override // 这是一个注解,表示覆盖从父类继承的方法
public void myMethod() {
// method body
}
用处:
提供文档信息:注解可以用于描述代码中的方法和变量,提供可读性更好的文档信息。
跟踪代码依赖性:注解可以用于标记代码中的依赖关系,方便跟踪和管理代码的依赖性。
实现AOP(面向切面编程):通过注解定义切面行为,实现非侵入式增强。
替代配置文件:注解可以用于简化配置和注入依赖关系的管理,减少配置文件的数量。
编译时检查:某些注解可以用于检查代码中的格式或参数,例如@Override注解用于检查方法是否覆盖了超类方法。
注解的分类:
预定义注解:包括常见的注解,如@Override、@Deprecated和@SuppressWarning等。这些注解通常用于标记代码中的特定元素,以便编译器在编译时进行警告或错误检查。
元注解:元注解是用于注解其他注解的注解,包括@Target、@Retention和@Inherited等。这些注解主要用于定义注解的元数据,例如注解的应用范围、注解的生命周期以及注解的继承方式等。
自定义注解:用户可以根据自己的需求定义注解。自定义注解可以根据需要添加参数和属性,以便更灵活地描述代码中的信息。
合理的使用注解可以在编译时进行检查,确保代码符合特定的规范或要求。但是同样注解也会增加代码的复杂度,使代码难以理解。注解有好处也有坏处,因此需要合理的使用注解。