Day16:JAVA反射
注
-
框架的底层都是注解和反射
-
实体类:pojo、entity
-
一个类在内存中只有一个Class对象
-
一个类被加载后,类的整个结构都会被封装在Class对象中
-
Alt加鼠标左键可以选中不同行但同列的空间
-
数组的类型与维度一样就是同一个Class
-
加载-链接-初始化
-
双亲委派机制:从上找类,找不到同名的再执行自定义类,否则不执行自定义类
注解
可以被其他程序读取(比如编译器等)
内置注解
@Override
@Deprecated
@SupperssWarnings(“”) //镇压警告
参数列表:
all:所有
unchecked:
..
元注解
负责注解其他注解
@Target(value = {ElementType.TYPE,ElementType.METHOD})
表示注解可以用在什么地方
@Retention(RetensionPolicy.RUNTIME)
SOURCE、CALSS、RUNTIME
表示在什么时候有效
@Documented
表示是否将注解生成到JAVAdoc中
@Inherited
子类可以继承父类的注解
自定义注解
@interface MyAnnotation{
//注解的参数:参数类型 + 参数名()
String name() default "";
int age() default 0;
String[] myClass() default {"嘻嘻","哈哈"};
}
参数类型只能是基本类型、Class、String、enum
default为参数值默认值
如@MyAnnotation(name = "",age=1)
注意:参数名为value时才可以省略不写
反射
主要API
java.lang.Class
java.lang.reflect.Method
java.lang.reflect.Field
java.lang.reflect.Constructor
方法
static Class forName(String name)
Object newInstance() //要获取的类必须得有一个无参构造,因为该方法调用的就是类的无参构造
getName()
getSimpleName()
Class getSuperClass()
Class[] getinterfaces()
ClassLoader getClassLoader()
Constructor[] getConstructors()
Method getMethod(String name,Class.. T) //c1.getMethod(“test”,null);c1.getMethod(“name”,String.class)
Field[] getDeclaredFields()
Method[] getMethods() //获取该类及其父类的public方法
Method[] getDeclaredMethods() //获取该类的所有方法
获取Class类的实例
-
Test.class
-
test.getClass()
-
Class.forName("test.Test")
-
基本内置数据类型即包装类.Type,如:Integer.Type
-
通过ClassLoader获取
哪些类可以有Class对象
calss:外部类、成员内部类、静态内部类、局部内部类、匿名内部类
interface:接口
[]:数组
enum:枚举
annotation:注解@interface
primitive type:基本数据类型
void
类加载器
自定义类加载器 -> 系统类加载器 -> 扩展类加载器 -> 引导类加载器
以上箭头->代表其父类
自底向上检查类是否已装载 -> 自顶向下尝试加载类
ClassLoader.getSystemClassLoader()
引导类加载器
C++编写,JVM自带类加载器,负责java平台核心库,用来装载核心类库;该加载器无法直接获取
java内置类是通过引导类加载器加载的
扩展类加载器
负责jre/lib/ext目录下的jar包或 -D java.ext.dirs 指定目录下的jar包装入工作库
系统类加载器
负责java -classpath 或 -D java.class.path所指的目录下的类与jar包装入工作,是最常用的加载器
动态
Constructor类也有一个newInstance()方法 //利用这构造器创建对象
Method类有一个invoke()方法来动态调用类的方法 //m1.invoke(实例,参数)
Filed类有get/set方法来获取/设置字段值 //f1.set(实例,"test")
当涉及到操作私有的属性、构造器或方法时会报非法权限异常,但可以用f1.setAccessible(true)/m1.setAccessible(true)来避免出现这个异常
性能对比
普通方式:最快
反射方式:最慢
关闭检测方式:中
操作泛型
-
Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换问题,但是,一旦编译完成,所有和泛型有关的类型全部擦除
-
为了通过反射操作这些类型,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型
-
ParameterizedType:表示一种参数化类型,比如Collection<String>
-
GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型
-
TypeVariable:是各种类型变量的公共父接口
-
WildcardType:代表一种通配符类型表达式
package test;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
public class TestReflectGeneric {
public void test01(Map<String,Test> m, List<Test> l){
System.out.println("test01");
}
public Map<Test,String> test02(){
System.out.println("test02");
return null;
}
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
Class c1 = Class.forName("test.TestReflectGeneric");
Method m1 = c1.getMethod("test01", Map.class, List.class);
Type[] genericParameterTypes = m1.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println(genericParameterType);
if(genericParameterType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
Method m2 = c1.getMethod("test02", null);
Type genericReturnType = m2.getGenericReturnType();
if(genericReturnType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
}
获取注解信息
ORM:Object Relationship Mapping 对象关系映射
-
类和表结构对应
-
属性和字段对应
-
对象和记录对应
注解名 注解实例名 =(注解名)c1.getAnnotation(注解名.class)
注解实例名.注解属性名()获取注解属性值