注解与反射
一.注解
Java注解提供了关于代码的一些信息,但并不直接作用于它所注解的代码内容,注解可以被一些解析工具或者编译工具进行解析,我们也可以声明注解在编译过程或执行时产生的作用。注解不仅包含了元数据,它还可以作用于程序运行过程中,注释解释器可以通过注解决定程序的执行顺序。
1.元注解
元注解的作用就是负责注解其他注解,Java5.0定义了四个标准的mete-annotion类型,它们被用来提供对其他annotion类型作说明
(1)Target
Target说明了Annoation所修饰的对象范围:Annotation可被用于packages,types(类,接口,枚举,Annotation类型),类型成员(方法,构造,方法,成员变量,枚举值),方法参数和本地变量(如循环变量,)在Annotation类型的声明中,使用了target可更加清晰明确器修饰的目标
取值有(ElementType)
1.CONSTRUCTOR:用于描述构造器
2.FIELD:用于描述域
3.LOCAL_VARIABLE:用于描述局部变量
4.METHOD:用于描述方法
5.PACKAGE:用于描述包
6.PARAMETER:用于描述参数
7.TYPE:用于描述类,接口(包括注解类型)或enum声明
(2)Retention
作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即被描述的注解在什么范围内有效)
取值:(RetentionPoicy)
1.SOURCE:在原码文件中有效
2.CLASS:在class文件中有效(即class保留)
3.RUNTIME:在运行时有效(即在运行时保留)
(3)Document
在产生DOC文档时使用,它是一个标记注解,没有成员
(4)Inherited
Inherited元注解是一个标记注解,阐述了某个被标注的类型是被继承的,
注意:@Inherited annotation类型是被标注过的class的子类所继承,类并不从他所实现的接口继承annotion,方法并不从它所重载的方法继承annotation
2.自定义注解
使用@Interface自定义注解时,自动继承了java.lang.annotation.Annotation,它用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数,方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型:Class,String,enum)可以通过default来声明参数的默认值
注意:只能用public或默认的default这两个访问权修饰,如果只有一个参数成员,最好把参数名称设为“value()”
package com.wang.demo2;
import java.lang.annotation.*;
public class MyTest {
@Myannotion1
public void test(){
}
@MyAnnotion2("我喜欢你")
public void test2(){
}
}
@Target(value = {ElementType.METHOD,ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@interface Myannotion1{
String name() default "";
int age() default 0;
int id() default -1;
String[] schools() default {"小明","小花"};
}
@Target(value = {ElementType.METHOD,ElementType.TYPE,ElementType.FIELD})//作用域
@Retention(RetentionPolicy.RUNTIME)//运行时级别
@Documented
@Inherited
@interface MyAnnotion2{
String value();
}
二.什么是反射
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所欲属性和方法,多余任意一个对象,都能够调用他的任意方法和属性,在具体的研发过程中,通过反射获取类的实例,大大提高系统的灵活性和扩展性,同时由于反射的性能较低,而且极大破坏了类的封装性(通过反射获取类的私有方法和属性)
注意:Class本身就是一个类,Class就是这个类的名称;public class MyTest{} 这里的class作为关键字,来表明Demo是一个类,数组类型一样的情况下,同个维度只有一个class对象
1.获取Class对象的三种方式
1.1Object–>getCLass();
1.2任何数据类型(包括基本数据类型)都有一个“静态”的class属性
1.3通过Class类的静态方法:(ForName)(String className)
package com.wang.demo2;
import java.sql.SQLOutput;
public class MyTest2 {
public static void main(String[] args) throws ClassNotFoundException {
// 通过反射来获取class
Class c1 = Class.forName("com.wang.demo2.MyTest2");
System.out.println(c1);
//通过创建方式来获取
User user = new User();
Class c2 = user.getClass();
System.out.println(c2);
Class c3 = MyTest2.class;
System.out.println(c3);
}
}
class User extends Object{
private String name;
private int age;
private int id;
public User() {
}
public User(String name, int age, int id) {
this.name = name;
this.age = age;
this.id = id;
}
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 int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", id=" + id +
'}';
}
}
package com.wang.demo2;
import java.lang.annotation.ElementType;
public class MyTest3 {
public static void main(String[] args) {
Class c1 = Object.class; //类
Class c2 = Comparable.class;//接口
Class c3 = String.class;
Class c4 = int.class;
Class c5 = String[][].class; //二维数组
Class c6 = ElementType.class; //枚举
Class c7= Override.class; //注解
Class c8 = Integer.class; //基本数据类型
Class c9 = Void.class;// void
Class c10 = Class.class;//Class
int[] a = new int[10];
int[] b = new int[100];
Class c11 =a.getClass();
Class c12 =b.getClass();
//数组类型一样的情况下 , 同个维度 , 只有一个class对象
System.out.println(c11==c12);
System.out.println(c3==c5);
System.out.println(c10);
System.out.println(c11);
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
System.out.println(c5);
System.out.println(c6);
System.out.println(c7);
System.out.println(c8);
System.out.println(c9);
}
}
输出结果:
true
false
class java.lang.Class
class [I
class java.lang.Object
interface java.lang.Comparable
class java.lang.String
int
class [[Ljava.lang.String;
class java.lang.annotation.ElementType
interface java.lang.Override
class java.lang.Integer
class java.lang.Void
2.通过反射获取构造方法并使用
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class MyTest4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1 = Class.forName("java.lang.Object");
String name = c1.getName();//获得包名+类名
String simpleName = c1.getSimpleName();//获得类名
System.out.println(name);
System.out.println(simpleName);
Field[] fields = c1.getFields();//只能获得类的public属性
for (Field field : fields) {
System.out.println(field);
}
Field[] declaredFields = c1.getDeclaredFields();//获得类的全部属性
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
Field name1 = c1.getDeclaredField("equals");//获得指定的属性值
name1.setAccessible(true);//解除私有限定
System.out.println(name1);
Method[] methods = c1.getMethods();//获取本类所有的public方法
for (Method method : methods) {
System.out.println(method);
}
System.out.println("===============================================");
Method[] declaredMethods = c1.getDeclaredMethods();//获得本类的所有方法
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
System.out.println("=========================================================");
Constructor constructor = c1.getConstructor(null);
System.out.println(constructor);//获得无参构造
Constructor constructor1 = c1.getConstructor(String.class, int.class,int.class);
System.out.println(constructor1);
}
}
3.通过动态构造对象,调用方法
package com.wang.demo2;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MyTest5 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class<?> c1 = Class.forName("com.wang.demo2.User");
//通过动态调用构造方法构造对象
User user = (User) c1.newInstance();
System.out.println("=======================================");
//通过有参构造创建对象
Constructor<User> declaredConstructor = (Constructor<User>) c1.getDeclaredConstructor(String.class, int.class, int.class);
User user1 = declaredConstructor.newInstance("张三", 001, 29);
System.out.println("===========================================");
//调用普通方法
User user2= (User) c1.newInstance();
Method setName = c1.getDeclaredMethod("setName", String.class);
setName.invoke(user2,"李四");
System.out.println(user2.getName());
System.out.println("==============================================");
//操作属性
User user3 = (User) c1.newInstance();
Field name = c1.getDeclaredField("name");
name.setAccessible(true);//关闭监测
name.set(user3,"王五");
System.out.println(user3.getName());
}
}
4.设置输出字体颜色
public class MyTest6{
public static void main(String[] args) {
System.out.println("\u001b[31m 杜兰特");//红色
System.out.println("\u001b[1;42m 你好");//控制输出背景颜色
System.out.println();
//有下划线
System.out.println("\033[32;4m 中国 \033[0m");
System.out.println("\033[30;4m 美国 \033[0m");
System.out.println("\033[31;4m 英国 \033[0m");
}
}
输出结果:
5.测试泛型获取泛型
public class MyTest7 {
public void test01(Map<String, User> map, List<User> list) {
System.out.println("这是test01");
}
public Map<Integer, User> test02() {
System.out.println("这是test02");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
//获得指定方法的泛型信息
Method method = MyTest7.class.getDeclaredMethod("test01", Map.class, List.class);
//获得泛型参数信息
Type[] t = method.getGenericExceptionTypes();
for (Type type : t) {
System.out.println("1" + type);
if (type instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
//获得真实的类型参数
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println("Really" + actualTypeArgument);
}
}
}
//获得返回值泛型信息
Method method1 = MyTest7.class.getMethod("test02");
//获得泛型参数类型信息
//获得泛型返回值信息
Type genericReturnType = method1.getGenericReturnType();
if (genericReturnType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println("真实的返回值泛型类型" + actualTypeArgument);
}
}
}
}
6.测试对象关系映射
public class Test{
public static void main(String[] args) throws Exception {
//通过反射获取注解信息
Class c1 = Class.forName("com.kuang.reflection.Student2");
Annotation[] annotations = c1.getAnnotations();//获得这个类的所有注解信息
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//获得注解的值
//通过注解的 value方法 获得注解的值
Annotation annotation = c1.getAnnotation(TableKuang.class);
TableKuang annotation1 = (TableKuang) annotation;
System.out.println(annotation1.value());
Field field = c1.getDeclaredField("id");
System.out.println(field);
//获得字段的注解
FieldKuang annotation2 = field.getAnnotation(FieldKuang.class);
//获得注解的参数信息
System.out.println(annotation2.columnName());
System.out.println(annotation2.length());
System.out.println(annotation2.type());
}
}
//学生的实体类
//db : database -->数据库
@TableKuang("db_student")
class Student2{
@FieldKuang(columnName = "id",type = "int",length = 10)
private int id;
@FieldKuang(columnName = "db_age",type = "int",length = 3)
private int age;
@FieldKuang(columnName = "name",type = "varchar",length = 20)
private String name;
public Student2() {
}
public Student2(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student2{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
//表名-->类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableKuang{
String value();
}
//字段类的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldKuang{
//参数类型 参数名
String columnName();//列名
String type();//类型
int length();//长度
}