一、注解
- 注解(Annotation)的作用:可以被其他程序(比如:编译器)读取。
@Override 重写注解
@Deprecated 表示不鼓励使用或者已经废弃,通常是因为它很危险或者存在更好的方法
@SuppressWarnings 用来抑制编译时的警告信息,传入“all”抑制所有警告
二、元注解
元注解的作用:负责注解其他注解(禁止套娃。。。
@Target 表示我们的注解可以用在哪些地方
@Retention 表示我们的注解在什么地方有效 runtime>class>sources 默认RUNTIME
@Documented 表示是否将我们的注解生成在Javadoc中
@Inherited 表示子类可以继承父类的注解
三、自定义注解
使用 @interface自定义注解,自动继承Annotation接口
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotarion{
//注解的参数:参数类型 + 参数名 ();
String value() default "";//参数名为value时,传参时可以省略value = ,不传参时,则为default默认值
}
四、反射
正常方式:引入需要的“包类”名称–>通过new实例化–>取得实例对象
加载类完成后,在堆内存的方法区就产生了一个Class类型对象,这个对象包含了完整的类的结构信息,可以通过这个对象看到类的结构
反射方式:实例化对象–>getClass()方法–>得到完整的“包类”名称
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException {
//通过反射获取类的class对象
Class c1 = Class.forName("Reflection.Person");
System.out.println(c1);
//一个类在内存中只有一个class对象
//一个类被加载后,类的整个结构都会被封装在Class对象中
Class c2 = Class.forName("Reflection.Person");
Class c3 = Class.forName("Reflection.Person");
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
}
}
class Person{
private String name;
private int id;
public Person() {
}
public Person(String name, int id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
获取Class类的实例
- 通过类名获取 Class c = Person.class();
- 通过实例对象获取 Class c = person.getClass();
- 通过包名 Class c = Class.forName(“Reflection.Person”)
- 基本数据类型可以直接用.TYPE Class c = Integer.TYPE
哪些类型可以有Class对象
- class 类
- interface 接口
- [] 数组
- enum 枚举
- annotation 注解@interface
- primitive type 基本数据类型
- void
类的加载过程(了解
类的加载(Load)–>类的链接(Link)–>类的初始化(Initialize)
加载:将类的class文件读入内存,并为之创建一个Class对象此过程有类加载器完成
链接:将类的二进制数据合并到JRE中
初始化:JVM负责初始化,当初始化一个类时,若发现其父类没有初始化,则先触发其父类的初始化
什么时候会发生类的初始化?
类的主动引用(一定会发生类的初始化
- 当虚拟机启动,先初始化main()方法所在的类
- new一个类的对象
- 调用类的静态成员(除了final常量)和静态方法
- 使用java.lang.reflect包的方法对类进行反射调用
- 当初始化一个类,如果其父类没有被初始化,则会初始化他的父类
类的被动引动(不会发生类的初始化
- 当访问一个静态域时,只有真正声明这个域的类才会被初始化(子类调用父类的静态变量,不会初始化子类
- 通过数组定义类引用,不会触发类的初始化
- 引用常量不会触发此类的初始化(常量链接阶段就存入调用类的常量池中了
类加载器
作用:将class文件字节码加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后再堆中生成一个代表这个类的Class对象,作为方法区中类数据的访问入口。
获取类的运行时结构
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c = Class.forName("Reflection.Person");
//获取类的名字
String name = c.getName();
System.out.println(name);//获取包名 + 类名
System.out.println(c.getSimpleName());//类名
//获取类的属性
System.out.println("---");
Field[] fields = c.getFields();//只能获得public属性
for (Field field : fields) {
System.out.println(field);
}
Field[] declaredFields = c.getDeclaredFields();//找到全部的属性
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
System.out.println(c.getDeclaredField("name"));//获得指定的属性
//获得类的方法
System.out.println("===");
Method[] methods = c.getMethods();//本类及其父类的全部方法
for (Method method : methods) {
System.out.println(method);
}
System.out.println("===");
Method[] declaredMethods = c.getDeclaredMethods();//获得本类的方法
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
//获得本类的指定方法
//参数考虑到重载
System.out.println(c.getMethod("setName", String.class));
//获得构造器
System.out.println("===");
Constructor[] constructors = c.getConstructors();//获得所有构造器 public
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println(c.getDeclaredConstructor(String.class,int.class));//不局限public的方法
}
}
动态创建对象
调用Class对象的newInstance()方法
1)类必须有一个无参构造器
2)类的构造器的访问权限需要足够
用构造器创建对象
调用方法、修改属性
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test03 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class c = Class.forName("Reflection.Person");
Person person = (Person) c.newInstance();//本质调用了无参构造器
System.out.println(person);
//通过构造器创建对象
System.out.println("===");
Constructor constructor = c.getDeclaredConstructor(String.class, int.class);
Person instance = (Person)constructor.newInstance("小王", 170788);
System.out.println(instance);
//通过反射调用普通方法
System.out.println("===");
Method method = c.getMethod("setName", String.class);
//invoke 激活的意思
method.invoke(instance,"大王");//使用invoke方法来传入使用此方法的对象和value
System.out.println(instance);
//通过反射操作属性
System.out.println("===");
Field name = c.getDeclaredField("name");
//不能直接访问private的属性,需要关闭程序的安全检测,利用如下方法
name.setAccessible(true);//true 这样就是可以访问了
name.set(instance,"小王");
System.out.println(instance);
//Methord,Field,Construtor 对象都有setAccessible()开关
}
}
性能问题
当访问权限为true时,这样会提高反射的效率
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test04 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
test01();
test02();
test03();
}
public static void test01(){
Person p = new Person();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
p.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方法的运行时间:" + (endTime - startTime) + "ms");
}
public static void test02() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class c = Class.forName("Reflection.Person");
Constructor constructor = c.getConstructor();
Person instance =(Person) constructor.newInstance();
Method method = c.getMethod("getName", null);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
method.invoke(instance,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方法的运行时间:" + (endTime - startTime) + "ms");
}
public static void test03() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class c = Class.forName("Reflection.Person");
Constructor constructor = c.getConstructor();
Person instance =(Person) constructor.newInstance();
Method method = c.getMethod("getName", null);
method.setAccessible(true);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
method.invoke(instance,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方法关闭安全检测的运行时间:" + (endTime - startTime) + "ms");
}
}
获取泛型信息
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 Test05 {
public void test01(Map<String ,Person> map, List<Person> list){
System.out.println("test01");
}
public Map<String,Person> test02(){
System.out.println("test02");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
Method method = Test05.class.getMethod("test01", Map.class, List.class);
Type[] genericParameterTypes = method.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);
}
}
}
System.out.println("===");
Method method1 = Test05.class.getMethod("test02");
Type genericReturnType = method1.getGenericReturnType();
System.out.println(genericReturnType);
if (genericReturnType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
}
反射操作注解(重要
import java.lang.annotation.*;
import java.lang.reflect.Field;
public class Test06 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class aClass = Class.forName("Reflection.Student");
//利用反射访问类的注解
Annotation[] annotations = aClass.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
Xiaowang xiaowang = (Xiaowang)aClass.getAnnotation(Xiaowang.class) ;
System.out.println(xiaowang.value());
//利用反射访问属性的注解
System.out.println("===");
Field field = aClass.getDeclaredField("name");
FieldWang annotation = field.getAnnotation(FieldWang.class);
System.out.println(annotation.columnName());
System.out.println(annotation.length());
System.out.println(annotation.type());
}
}
@Xiaowang("db_student")
class Student{
@FieldWang(columnName = "db_name",type = "db_String",length = 10)
private String name;
@FieldWang(columnName = "db_id",type = "db_int",length = 10)
private int id;
public Student() {
}
public Student(String name, int id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Xiaowang{
String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldWang{
String columnName();
String type();
int length();
}