注解与反射
11.20 12.3 12.11
1、注解
1.1、元注解
@Retention:指定其所修饰的注解的保留策略
@Document:该注解是一个标记注解,用于指示一个注解将被文档化
@Target:用来限制注解的使用范围
@Inherited:该注解使父类的注解能被其子类继承
@Repeatable:该注解是Java8新增的注解,用于开发重复注解
类型注解(Type Annotation):该注解是Java8新增的注解,可以用在任何用到类型的地方
1.2、注解
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE,FIELD,TYPE_PARAMETER,TYPE_USE}) //指明MyAnnotation可以修饰哪些元素,不写的话就是全部可以 TYPE_PARAMETER修饰泛型 TYPE_USE修饰类型
@Documented //表示MyAnnotation在被javadoc解析时,MyAnnotation注解标识被保留下来
@Inherited //表示MyAnnotation具有继承性,子类自动有这个注解
@Repeatable(MyAnnotations.class)//可重复注解 //注意是MyAnnotations,不是MyAnnotation
public @interface MyAnnotation {
String value() default "hellolxw";
}
可重复注解
//所有的元注解信息与MyAnnotation需相同
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE,FIELD})
@Documented //表示MyAnnotation在被javadoc解析时,MyAnnotation注解标识被保留下来
@Inherited
public @interface MyAnnotations {
MyAnnotation[] value();
}
/**
* @author liuxuewei
*/
public class Test2210131 {
public static void main(String[] args) {
Class<People> peopleClass = People.class;
Annotation[] annotations = peopleClass.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
Class<PeopleSon> peopleSonClass = PeopleSon.class;
Annotation[] annotations1 = peopleSonClass.getAnnotations();
for (Annotation annotation : annotations1) {
System.out.println(annotation);
}
Class<Peoples> peoplesClass = Peoples.class;
Annotation[] annotations2 = peoplesClass.getAnnotations();
for (Annotation annotation : annotations2) {
System.out.println(annotation);
}
}
@MyAnnotation("lxw2")
@Data
public static class People {
private int id;
private String name;
}
@EqualsAndHashCode(callSuper = true)
@Data
public static class PeopleSon extends People{ //也被解析出@MyAnnotation("lxw2") 是因为@Inherited 继承性
}
@Data
@MyAnnotation("lxw1")
@MyAnnotation("lxw2")
public static class Peoples {
}
public static class Generic<@MyAnnotation T> { //TYPE_PARAMETER
public void show() throws @MyAnnotation RuntimeException{ //TYPE_USE
ArrayList<@MyAnnotation String> list = new ArrayList<>(); //TYPE_USE
int num = (@MyAnnotation int)10L; //TYPE_USE
}
}
}
输出:
@test221013.MyAnnotation(value=lxw2)
@test221013.MyAnnotation(value=lxw2)
@test221013.MyAnnotations(value=[@test221013.MyAnnotation(value=lxw1), @test221013.MyAnnotation(value=lxw2)])
2、反射
/**
* 反射
* @author liuxuewei
*/
public class Test22110201 {
public static void main(String[] args) throws Exception {
Class<People> peopleClass = People.class;
Constructor<People> constructor = peopleClass.getConstructor(Integer.class, String.class);
People people = constructor.newInstance(14,"Ydd");
System.out.println(people);
//【直接修改age属性值】
Field age = peopleClass.getDeclaredField("age");//获取属性
age.set(people, 15);//age是属性,people是修改的对象,15是修改的属性的值
System.out.println(people);
//【直接修改name属性值【private】】
Field name = peopleClass.getDeclaredField("name");
name.setAccessible(true);//调用私有private的需要加这个
name.set(people, "yddnb");
System.out.println(people);
//通过getset修改name属性值
Method setName = peopleClass.getDeclaredMethod("setName", String.class);
setName.invoke(people, "yddddd");
System.out.println(people);
//调用private的方法
Method show = peopleClass.getDeclaredMethod("show");
show.setAccessible(true);//private私有方法
String invoke = (String) show.invoke(people);//返回值就是show的返回值
System.out.println(invoke);
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class People{
public Integer age;
private String name;
private String show(){
System.out.println("my name is " + name);
return "hello";
}
}
}
输出:
Test22110201.People(age=14, name=Ydd)
Test22110201.People(age=15, name=Ydd)
Test22110201.People(age=15, name=yddnb)
Test22110201.People(age=15, name=yddddd)
my name is yddddd
hello
2.1、理解*封装和反射
反射会破坏对象的封装性
反射会破坏单例【再回去把狂神的反射刷一遍】
什么时候会使用到反射的方式。【动态性】编译的时候不确定new哪个对象。
2.2、理解*Class类的理解
1.java.long.Class类的加载过程
javac.exe,会生成一个或多个字节码文件.class
使用java.exe这个命令对某个字节码文件进行解释运行,将字节码文件加载到内存中,加载到内存中的类,就是运行时类,就是class的一个实例。
Class的实例就对应一个运行时类
加载到内存中的运行时类,会缓存一定的时间
2.3、理解*类的初始化
当程序主动使用某个类时,该类未加载到内存中,则系统会通过如下步骤对该类进行初始化。
1.类的加载【Load】
2.类的链接【Link】
3.类的初始化【initialize】
具体解释:
了解:ClassLoader
引导类加载器 Bootstap ClassLoader 该加载器无法直接获取
拓展类加载器 Extension ClassLoader 主要负责jre/lib/ext里的jar包
系统类加载器 System ClassLoader 我们写的类都在这里加载
自定义类加载器 可以自定义,一般也用不到
public class Test221120 {
public static void main(String[] args) {
//自定义类,系统类加载类加载
ClassLoader classLoader = Test221120.class.getClassLoader();
System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2
//获取拓展类加载器
System.out.println(classLoader.getParent());//sun.misc.Launcher$ExtClassLoader@2626b418
//引导类加载器无法获取[主要负责java类库,无法加载自定义类的]
System.out.println(classLoader.getParent().getParent());//null
//看看String类的加载器
ClassLoader classLoader1 = String.class.getClassLoader();
System.out.println(classLoader1);//输出null说明String的加载器就是引导类加载器
}
}
2.4、通过反射获取配置文件properties等
person.properties
name=ydd
age=250
main
Properties properties = new Properties();
//FileInputStream inputStream = new FileInputStream("person.properties");
ClassLoader classLoader = Test221120.class.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream("person.properties");
properties.load(inputStream);
String name = properties.getProperty("name");
String age = properties.getProperty("age");
System.out.println(name);
System.out.println(age);
2.5、通过反射创建运行时类的对象
直接创建运行时类的对象newInstance
Class<Person> personClass = Person.class;
Person person = personClass.newInstance();//本质上还是调用Person的空参构造器的方式。只有构造器才能创建对象
System.out.println(person);
体会在运行过程中创建不同对象的作用
Demo【运行时根据某条件生成不同对象】
/**
* 运行时根据某条件生成不同对象
*
* @author liuxuewei
*/
public class Test1120 {
public static void main(String[] args) throws Exception{
for (int j = 0; j < 5; j++) {
String name = "";
int i = new Random().nextInt(3);//控制随机条件生成不同对象
if (i==0){
name = "java.util.Date";
}
if (i==1){
name = "test1120.Person";
}
if (i==2){
name = "java.lang.Object";
}
Object object = getObjectByName(name);
System.out.println("j:"+i+"_"+object);
}
}
/**
* 通过name创建指定类的对象
*/
public static Object getObjectByName(String name) throws Exception{
final Class<?> aClass = Class.forName(name);
return aClass.newInstance();
}
}
2.6、反射获取类的内部值
前置,定义Person,Father类,一个接口MyInterface,一个注解MyAnnotation
@EqualsAndHashCode(callSuper = true)
@Data
@MyAnnotation("ClassPerson")
public class Person extends Father<String> implements Comparable<String>, MyInterface{
@MyAnnotation("==personName==")
private String personName;
int personAge;
public int personId;
@MyAnnotation("method-personShow")
public String personShow(String show){
System.out.println("the show is go on");
return show;
}
@Override
public int compareTo(String o) {
System.out.println("Person比较,暂未实现");
return 0;
}
@Override
public void info() {
System.out.println("this is Person");
}
}
@Data
public class Father<T> implements Serializable {
private char fatherGender;
public double fatherWeight;
private T t;
private void fatherBreath(){
System.out.println("father呼吸");
}
public void fatherEat(){
System.out.println("father吃东西");
}
}
public interface MyInterface {
void info();
}
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "hello";
}
获取运行时类的属性Test
/**
* 获取运行时类的属性
*
* @author liuxuewei
*/
public class TestFieldGet {
public static void main(String[] args) {
//获取属性(包括父类,只有public)
Class<Person> personClass = Person.class;
Field[] fields = personClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("############");
//获取当前运行时类的所有属性(包括各种权限)
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
int modifiers = declaredField.getModifiers();
System.out.println(modifiers);
System.out.println(Modifier.toString(modifiers));//权限修饰符
Class<?> type = declaredField.getType();//数据类型
System.out.println(type);
System.out.println(declaredField.getName());//变量名
}
}
}
获取运行时类的方法Test
/**
* 获取运行时类的方法
*
* @author liuxuewei
*/
public class TestMethod {
public static void main(String[] args) {
Class<Person> personClass = Person.class;
//获取运行时类所有public方法,包括父类
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
//获取运行时类的自己的所有方法,不包括父类
Method[] declaredMethods = personClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
for (Method declaredMethod : declaredMethods) {
//获取注解
Annotation[] annotations = declaredMethod.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//权限修饰符
System.out.println("方法权限修饰符"+Modifier.toString(declaredMethod.getModifiers()));
//返回值类型
System.out.println("返回值类型"+declaredMethod.getReturnType().getName());
//方法名
System.out.println("方法名"+declaredMethod.getName());
//形参
for (Class<?> parameterType : declaredMethod.getParameterTypes()) {
System.out.println("形参"+parameterType);
}
//抛出的异常
for (Class<?> exceptionType : declaredMethod.getExceptionTypes()) {
System.out.println("异常"+exceptionType.getName());
}
}
}
}
获取构造器同理
获取父类
/**
* 获取运行时类的父类的泛型
* @author liuxuewei
*/
public class TestClassGet {
public static void main(String[] args) {
Class<Person> personClass = Person.class;
Type genericSuperclass = personClass.getGenericSuperclass();
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
System.out.println(actualTypeArguments[0].getTypeName());
System.out.println(((Class) actualTypeArguments[0]).getName());
}
}
2.7、调用运行时的结构
//调用属性
public class TestRun {
public static void main(String[] args) throws Exception {
Class<Person> personClass = Person.class;
Person person = personClass.newInstance();
Field personName = personClass.getDeclaredField("personName");
personName.setAccessible(true);//修改权限
personName.set(person, "yddyyds");
System.out.println(person);
}
}
//调用方法
public class TestRun {
public static void main(String[] args) throws Exception {
Class<Person> personClass = Person.class;
Person person = personClass.newInstance();
Method personShow = personClass.getDeclaredMethod("personShow", String.class);
personShow.setAccessible(true);//权限
Object yddShow = personShow.invoke(person, "yddShow");//调用
System.out.println(yddShow);//返回值
//静态方法的话,无需指定具体的对象
}
}
评论区