一、 注解
注解介绍
1.内置注解
2.元注解
实例操作:
3. 自定义注解
实例:
二、反射
1. 反射的定义:
代码范例:
结果:
这里我报了一个错误,说是User找不到,找了很久才发现,是reflection下面的user,而不是test01下面的。
2. 获取Class类的创建方式
1.先创建一个实体类:(以下都是写在一个Java文件里面)
class Person{
String name;
public Person(){}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
2.写继承他的方法
class Student extends Person{
public Student() {
this.name="学生";
}
}
class Teacher extends Person{
public Teacher() {
this.name = "老师";
}
}
3.写主类,去获取他
//测试Class类的创建方式有哪些
public class test02 {
public static void main(String[] args) throws ClassNotFoundException {
Person one = new Student();
System.out.println("这个人是"+one.name);
//方式1:通过对象获取
Class c1 = one.getClass();
System.out.println(c1);
//方式2:通过forName获取
Class c2 = Class.forName("com.zhang.annotationAndreflection.reflection.Person");
System.out.println(c2);
//方式3: 通过类名.class
Class c3 = Student.class;
System.out.println(c3);
//方式4:基本内置类型的包装类都有一个type属性
Class c4 = Integer.TYPE;
System.out.println(c4);
//获取父类类型
Class c5 = c1.getSuperclass();
System.out.println(c5);
}
}
结果:
3. 获取所有的class对象
public class test03 {
public static void main(String[] args) {
Class c1 = Object.class;//对象的class
Class c2 = Comparable.class;//接口的class
Class c3 = String[].class;//一维数组的
Class c4 = int[][].class;//二维数组的
Class c5 = Override.class;//注解的
Class c6 = Element.class;//枚举类型
Class c7 = Integer.class;//基本数据类型
Class c8 = void.class;//空
Class c9 = 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);
System.out.println(c9);
//只要元素类型与维度与类型一样,就是同一个class
System.out.println(new int[10].getClass().hashCode());
System.out.println(new int[100].getClass().hashCode());
}
}
结果:
4. 对于类加载器的内存分析
上有三个重要的点需要知道,
一个是加载中什么时候生成的,
一个是链接中什么时候分配的内存,
一个是初始化类构造器的方法是谁
代码示例:
结果:
5. 类的初始化
package com.zhang.annotationAndreflection.reflection;
public class test05 {
static {
System.out.println("主类的初始化");
}
public static void main(String[] args) throws ClassNotFoundException {
// 主动引用
// Son son = new Son();
// 反射的主动引用
// Class.forName("com.zhang.annotationAndreflection.reflection.Son");
// 不会产生类的引用的方法
// System.out.println(Son.a);
// Son[] son = new Son[4];
// System.out.println(Son.R);
}
}
class Father{
static int a = 10;
static {
System.out.println("父类的初始化");
}
}
class Son extends Father{
static int m = 220;
static {
System.out.println("子类的初始化方法");
m = 20;
}
static final int R = 1;
}
当调用主动引用时,输出结果为:
即,当子类初始化时,如果父类没有初始化,那么会先对父类进行初始化。
调用反射获得相同的结果,所以反射也是主动引用。
当调用son.a时会输出
所以当子类对象调用父类的变量或者方法时,父类会被初始化,而子类则不会。
当子类对象声明参数时,即:Son[] son = new Son[4] 时,结果为:
所以声明时,不会对类进行初始化。
而调用子类对象中的静态变量时,即 System.out.println(Son.R);
结果为:
所以,调用静态变量也不会初始化类。
所以,前两种算是主动引用,而后三种则是被动引用。
6 类加载器
代码实例:
public class test06 {
public static void main(String[] args) throws ClassNotFoundException {
// 获取系统类的加载器
ClassLoader loader = ClassLoader.getSystemClassLoader();
System.out.println(loader);
// 获取系统类的加载器的父加载器
ClassLoader loaderParent = loader.getParent();
System.out.println(loaderParent);
// 获取系统类的根加载器
ClassLoader loaderGrander = loaderParent.getParent();
System.out.println(loaderGrander);
//测试当前类是哪个加载类留下的
ClassLoader classLoader = Class.forName("com.zhang.annotationAndreflection.reflection.test06").getClassLoader();
System.out.println(classLoader);
//测试JDK内置的类是谁加载的
classLoader = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader);
//如何获取系统类加载器可以加载的路径
System.out.println(System.getProperty("java.class.path"));
}
}
结果:
补充:
双亲委派机制:
7 获取类运行时的结构
实现代码:
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c = Class.forName("com.zhang.annotationAndreflection.reflection.User");
User user = new User();
c = user.getClass();
System.out.println(c.getName());
System.out.println(c.getSimpleName());
Field[] field = c.getFields(); //输出结果为null,是因为它只能找到public属性
field = c.getDeclaredFields();
for (Field f : field){
System.out.println(f);
}
Field name = c.getDeclaredField("name"); // 获取指定属性的值
System.out.println(name);
Method[] m1 = c.getMethods();
for (Method m : m1){
System.out.println(m);
}
Method[] m2 = c.getDeclaredMethods();//他与上面的不同就是他会获取所有的类,但上面的只能获取公共类
for (Method m : m2){
System.out.println(m);
}
// 获取指定方法名
// 为什么需要参数,因为重载的原因
Method getName = c.getMethod("getName",null);
Method setName = c.getMethod("setName", String.class);
System.out.println(getName);
System.out.println(setName);
// 获取指定的构造方法
Constructor[] constructors = c.getConstructors();
for (Constructor constructor : constructors){
System.out.println(constructor);
}
constructors = c.getDeclaredConstructors();
for (Constructor constructor : constructors){
System.out.println("----------"+constructor);
}
// 获取指定的构造器
// 获取指定的构造器
Constructor del = c.getDeclaredConstructor(String.class, int.class, int.class);// 这里获取的构造器就是有参构造器,如果User里面没有有参构造就会报错
System.out.println("获取指定的构造器"+del);
}
8. 动态创建对象执行方法
获取参数:
调用方法:
跳过安全检查:
通过反射动态的创建对象
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
// 获取class对象
Class c = Class.forName("com.zhang.annotationAndreflection.reflection.User");
// 构造一个对象
User user = (User)c.newInstance(); // 本质是调用了类的无参构造
System.out.println(user);
// 通过构造器创建对象 Constructor 构造器
Constructor constructor = c.getDeclaredConstructor(String.class,int.class,int.class);
User user2 = (User)constructor.newInstance("张三",001,18);
System.out.println(user2 +"的name是"+ user2.name);
// 通过反射调用普通方法
User user3 = (User)c.newInstance();
// 通过反射获取一个方法
Method setName = c.getDeclaredMethod("setName", String.class);
// invoke(对象,方法的值) 激活
setName.invoke(user3,"李四");
System.out.println(user3.getName());
// 通过反射操作属性->字段
User user4 = (User)c.newInstance();
Field field = c.getDeclaredField("name");
field.setAccessible(true); // 不能直接操作私有属性,要关闭程序的安全监测
field.set(user4,"王二麻子");
System.out.println(user4.getName());
}
运行结果:
当分别用不同的方法调用所需要的时间
// 分析性能问题
public class Test10 {
// 普通方法调用
public static void test01(){
User user = new User();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方法调用共用时间为:"+(endTime-startTime)+"ms");
}
// 反射方法调用
public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class c = user.getClass();
Method getName = c.getDeclaredMethod("getName", null);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方法调用共用时间为:"+(endTime-startTime)+"ms");
}
// 反射方法调用 关闭监测
public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class c = user.getClass();
Method getName = c.getDeclaredMethod("getName", null);
getName.setAccessible(true);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("关闭检测调用共用时间为:"+(endTime-startTime)+"ms");
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
test01();
test02();
test03();
}
}
结果:
9.获取泛型信息
获取泛型的实例:
public class Test11 {
public void test01(Map<String, User> map, List<User> list){
System.out.println("test01");
}
public Map<String, User> test02(){
System.out.println("test02");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
Method method = Test11.class.getMethod("test01",Map.class,List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
for(Type gen: genericParameterTypes){
System.out.println("#:"+gen);
if(gen instanceof ParameterizedType){ // 如果gen的类型是否是一个参数化类型
Type[] actualTypeArguments = ((ParameterizedType) gen).getActualTypeArguments(); // 强制转换获取真实参数信息
for(Type act : actualTypeArguments){
// 打印出泛型的参数信息
System.out.println(act);
}
}
}
method = Test11.class.getMethod("test02",null);
Type genericReturnType = method.getGenericReturnType();
if(genericReturnType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); // 强制转换获取真实参数信息
for(Type act : actualTypeArguments){
// 打印出泛型的参数信息
System.out.println(act);
}
}
}
}
结果:
10.通过反射调用注解
以下代码都在一个Java文件里面
创建一个类的注解:
// 类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableZhang{
String value();
}
创建一个反射的注解:
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldZhang{
String columnName();
String type();
int length();
}
随便创建一个类(get、set、toString删去了):
@TableZhang("db_bear")
class Bears{
@FieldZhang(columnName = "db_id", type = "int", length = 10)
private int id;
@FieldZhang(columnName = "db_age", type = "int", length = 10)
private int age;
@FieldZhang(columnName = "db_name", type = "varchar", length = 3)
private String name;
public Bears(){}
public Bears(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
}
主函数调用方法:
public class Test12 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class aClass = Class.forName("com.zhang.annotationAndreflection.reflection.Bears");
// 通过反射获得注解
Annotation[] annotations = aClass.getAnnotations();
for (Annotation annotation : annotations){
System.out.println(annotation);
}
// 获得注解value的值
TableZhang zhang = (TableZhang) aClass.getAnnotation(TableZhang.class);
String value = zhang.value();
System.out.println(value);
// 获得类指定的注解
Field name = aClass.getDeclaredField("name");
FieldZhang annotation = name.getAnnotation(FieldZhang.class);
System.out.println(annotation.columnName());
System.out.println(annotation.type());
System.out.println(annotation.length());
}
}
结果: