1. 自定义注解 @interface
@interface MyAnno {
//注解类型: 参数类型 参数名() defult 默认值;
String name() default "";
int age() default 0;
int id() default -1;
String[] schools(); //无默认值,那外部写这个注解时就必须带参数!
}
//测试类
public class Test {
@MyAnno(name = "jiaxin")
public void test () {
....
}
}
2.元注解
//表示我们的注解可以用在哪些地方
@Target(value = {ElementType.METHOD , ElementType.ANNOTATION_TYPE})
//表示我们的注解在什么地方还有效 runtime > class > sources
@Retention(value = RetentionPolicy.RUNTIME)
//表示是否将我们的注解生成在java doc中
@Documented
//子类可以继承父类的注解
@Inherited
@interface MyAnno {
}
3.注解种类:
内置注解+元注解+自定义注解
1.反射机制是Java被视为动态语言的关键,在框架Spring、Mybatis代码中有所体现。
2.如何创建对象? new 或者 clone()克隆 或者 反射!!
3.反射与注解相结合。 反射可以获取类的内部信息,动态化(运行时刻可以查看、改变其结构的)。
4.比较:
正常方式:引入包类名-new-获取实例化对象
反射方式:实例化对象-getClass()-得到完整的包类名称
5.反射机制提供的功能:
判断任一对象所属的类
构造任一类的对象
判断任一类所具有的属性和方法
获取泛型信息
处理注解
调用任一个对象的成员变量及方法
生成动态代理
....
6.优缺点:
优:实现动态创建对象和编译+灵活性
缺:影响性能
package com.tencent.reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
public class Test8 {
public static void t1() {
User user = new User();
long startTime = System.currentTimeMillis();
for(int i = 0; i < 1000000000 ; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime + "ms"); //5-6ms
}
public static void t2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class c1 = user.getClass();
Method getName = c1.getDeclaredMethod("getName" , null);
getName.setAccessible(false);
long startTime = System.currentTimeMillis();
for(int i = 0; i < 1000000000 ; i++) {
getName.invoke(user , null);
}
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime + "ms"); //5-6ms
}
public static void t3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class c1 = user.getClass();
Method getName = c1.getDeclaredMethod("getName" , null);
getName.setAccessible(true);
long startTime = System.currentTimeMillis();
for(int i = 0; i < 1000000000 ; i++) {
getName.invoke(user , null);
}
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime + "ms"); //5-6ms
}
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
System.out.print("普通调用getName():");
Test8.t1();
System.out.print("开启安全检测,调用getName():");
Test8.t2();
System.out.print("关闭安全检测,调用getName():");
Test8.t3();
/*
普通调用getName():6ms
开启安全检测,调用getName():1917ms
关闭安全检测,调用getName():1295ms
---说明反射消耗性能,费时.
* */
}
}
7.获取Class类的几种方法
package com.tencent.reflection;
public class Test2 {
public static void main(String[] args) throws ClassNotFoundException {
//1.通过对象 调用getClass()获取
User user = new User("jx" , 21);
Class c1 = user.getClass();
System.out.println(c1.hashCode());
//2.通过类的class属性获取
Class c2 = User.class;
System.out.println(c2.hashCode());
//3.通过类路径获取 forName()
Class c3 = Class.forName("com.tencent.reflection.User");
System.out.println(c3.hashCode());
//4.内置基本数据类型 包装类
Class c4 = Integer.TYPE;
System.out.println(c4); //int
//5.获得对象所属类的父类类型
System.out.println(c1.getSuperclass());
}
}
8.哪些类型具有Class对象(or 属性)?
package com.tencent.reflection;
import sun.reflect.generics.scope.ClassScope;
import java.lang.annotation.ElementType;
public class Test3 {
public static void main(String[] args) {
Class c1 = Object.class; //类
Class c2 = Comparable.class; //接口
Class c3 = String[].class; //数组
Class c4 = Override.class; //注解
Class c5 = ElementType.class; //枚举
Class c6 = Integer.class; //基本数据类型
Class c7 = void.class; //void
Class c8 = Class.class; //Class
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);
//元素类型相同,则获取对应的Class类型都相同
int[] a = new int[10]; //1163157884
int[] b = new int[100]; //1163157884
System.out.println(a.getClass().hashCode());
System.out.println(b.getClass().hashCode());
}
}
9.Java内存分析
栈:存放基本数据类型+引用对象的变量地址
堆:存放对象+数组,可被所有线程共享,注:存放Class对象!
方法区:被所有线程共享,存放 static静态变量
10.类加载过程
分三步
类加载Load + 类链接Link + 类初始化Initialize
a.加载: class文件字节码,加载到内存中,将静态数据转换成方法区的运行时数据结构,在堆中生成Class对象
b.链接:
验证:检查类信息符合JVM规范,有无安全问题;
准备:为类变量,即:静态变量,分配内存,设置默认初始值;
解析:虚拟机常量池,符号引用 替换为 直接引用地址 的过程。
c.初始化:
执行类构造器clinit()的过程;
初始化一个类,要检查其父类,先初始化父类;
虚拟区要确保一个类的构造器clinit()在多线程环境下,加锁及同步的进行。
11.什么情况发生类的初始化?
主动引用会发生;被动引用不会。
主动引用:略;
引言:主动引用中,当前程序执行的Main方法一定会初始化。
被动引用:
a. 访问静态域的话,是真正声明这个域的类才会初始化!例如:
通过子类引用父类的静态变量,则不会引起子类的初始化!只会引起父类的初始化。
b. 通过数组定义类访问时,不会加载当前定义类的初始化!
c. 引用常量。 不会引起当前定义类的初始化!
因为常量在链接的第三步解析步骤下,就会调入常量池中了。