目录

  • 注解
    • 内置注解
    • 元注解
  • 反射
    • 获取class的三种方式
    • class对象的范围
    • Java内存
      • 类使用过程
      • 类的初始化
    • 类加载器
    • class类方法
    • 反射创建实例和使用
    • 性能对比
    • 获取泛型参数类型
    • 通过反射获取注解和注解参数值

注解

JDK5引入的

作用:1 可以对程序做出解释 2 可以让编译器读取(通过反射)
格式:@XXXX(xxx=xxx)

内置注解

@Override
@Deprecated
@SuppressWarnings:抑制编译时的警告信息

元注解

作用:负责注解其他注解,java定义了4个元注解

  1. @Target:描述注解的使用范围
  2. @Retention:描述注解的声明周期级别(source<class<runtime),一般都是runtime
  3. @Document:描述注解将被包含在javadoc中
  4. @Inherited:描述子类可以继承父类中的该注解

定义一个注解使用@interface

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Demo05 {// 定义注解的参数:参数类型 参数名()String name() default "pp";String[] age();
}

注意:如果注解只有一个参数,则最好该参数名为value,因为value可以省略

反射

Java、C、C++都是静态语言。
Object-C、C#、JavaScript、PHP、Python等都是动态语言,即运行时的代码可以根据条件改变滋生的结构。

Java虽然不是动态语言,但是可以通过反射机制获得一定的动态特性。 可以实现动态编译和创建对象,但是反射削弱了安全性,性能也较慢于直接执行正向操作。

Reflection:是Java动态行式的关键,可以借助反射API获取任何类的内部信息,并且可以操作其中的方法和属性。

类加载方法:Class c = Class.forName("java.lang.String")
类加载进内存,实际上进了方法区,产生一个字节码对象,然后可以实例化该对象,实例化对象存在堆内存中,可以操作该对象。
* 加载类:方法区
* 实例化:堆内存

需要掌握的反射API:
java.lang.Class
java.lang.reflect.Method|Field|Constructor

注意:对象的getClass方法,返回的是用来new的那个类,如:Person p = new Student();System.out.println(p.getClass());返回的是Student类。

获取class的三种方式

  1. 通过对象.getClass()
  2. 通过静态方法:Class.forName(xxx)
  3. 通过字节码:xxx.class

注意:无论通过哪种方式,同一个类的字节码唯一

获取类的父类类型,通过class对象的该方法:getSuperClass()

class对象的范围

以下类型都有class对象:

Java内存

  • 方法区:所有线程共享,类字节码的动态运行结构和static变量,方法
  • 堆:所有线程共享,new出来的对象
  • 栈:基本数据类型,引用类型的变量(指向堆内存)

类使用过程

当java程序需要某个类的时候,java虚拟机会确保这个类已经被加载、连接和初始化,而连接这个类的过程分为3个步骤。

  1. 加载:class文件加载进入内存,静态代码转换成方法区的运行时数据结构,生成对应的Class对象(比如:java.lang.Class)

  2. 链接:将类的二进制代码与JVM运行状态合并
    a. 验证:该类符合JVM规范
    b. 准备:将static变量分配内存空间并赋初值,在方法区中
    c. 解析:将虚拟机常量池的符号引用替换成引用地址

  3. 初始化
    a. 执行类构造器:<clinit>(),该构造器由编译期自动收集类中所有类变量赋值静态代码块中的语句合并产生的

    类变量和静态代码块都是在构造方法执行前执行的

    b. 初始化时必须从父类开始
    c. JVM保证类构造器方法在多线程中正确加锁和同步

Demo:

public class A {public static void main(String[] args){B b = new B();System.out.println(b.m);}
}
public B{static {System.out.println("B静态代码块");m = 300;}static int m = 100;public B(){System.out.println("B无参构造");}

分析上面过程:

  1. 启动JVM,将A、B两个类加载进内存行程class对象,放在方法区! 堆空间形成两个引用变量:A和B,并指向方法区class对象
  2. 链接过程:开始执行类的静态属性初始化,如int类型则赋值为0。
  3. 初始化过程:合并static代码(静态代码块和类变量),**按顺序!**执行!
  4. 进入主函数,看到new B()代码,然后进入构造方法执行

类的初始化

该过程是类加载进方法区的第三阶段:初始化

当发生下面几种情况时,类会初始化:

  • 虚拟机启动,main方法所在的类会被初始化
  • new 一个类的对象
  • 调用类静态成员和静态方法(除final常量)
  • 使用反射包下的方法
  • 继承关系会层层初始化

当发生下面关系,类不会初始化:

  • 子类引用父类静态变量,子类不会加载,父类会被初始化
  • 定义对象数组,该对象不会被初始化!X[] x = new X[10]
  • 引用常量,不会初始化类,常量在链接阶段已经存入调用类的常量池中了

类加载器

类被加载器加载后,会维持一段时间缓存,如果没有使用,最终会被GC回收

类加载器有三种:

  1. 引导类:用C++编写,JVM自带的,负责Java核心库(rt.jar),无法直接获取
  2. 扩展类:加载jre/lrt.jar)ib/ext下的包或者-D java.ext.dirs目录下的包加载
  3. 系统类:加载java -classpath或-D java.class.path目录下的类包(最常用)

继承关系:引导(Bootstap)>扩展(extension)->系统(System)->自定义
顶级是引导类加载器,java无法直接通过调用getParent方法获取,是C编写的

判断当前类是哪个加载器加载的:
class.forName("xxx").getClassLoader();

获取类加载器可加载的路径:
System.getProperty("java.class.path")

双亲委派机制:为了保护扩展类和核心类的正确安全加载,如果系统类加载器目录中存在其上两种加载器类中存在的类,则不会被加载。简单地说,引导类和扩展类会覆盖系统类中的同全名类。 再简单点说就是:你不配重写我的类!

class类方法

getName:获取类全名
getSimpleName:获取类名
getFields:获取public属性
getDeclaredFields:获取所有属性
getMethods:获取 本类及父类 所有public方法
getDeclaredMethods:获取 本类 所有方法
getConstructors
getDeclaredConstructors

可以指定获取方法,入参为方法名和入参:getMethod("xxx",XXX.class)

反射创建实例和使用

demo:

// 无参构造创建实例,必须保证类有无参构造器
Class c1=Class.forName("xxx");
XXX xxx=(XXX)c1.newInstance();// 有参构造实例
Constructor con=c1.getDeclaredConstructor(xx.calss,yy.class);
XXX xxx=(XXX)con.newInstance(a,b);// 调用类方法,相当于调用实例对象的方法
c1.getDeclaredMethod(方法,参数).invoke(实例对象,参数);// 调用属性
Field 属性名=c1.getDeclaredField(属性名);
属性名.set(对象名,参数);
// 当属性为私有,则需要打开访问权限,如果频繁使用反射,则建议打开可以提升效率
属性名.setAccessible(true)

性能对比

直接Demo:

package com.xiaopi3;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class Demo07 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {test01();test02();test03();}public static void test01(){User user = new User();long startTime = System.currentTimeMillis();for (int i = 0; i < 1000000000; i++) {user.getName();}long endTime = System.currentTimeMillis();System.out.println("01:"+(endTime-startTime)+"ms");}public static void test02() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {User user = new User();Class<?> c1 = user.getClass();Method getName = c1.getDeclaredMethod("getName", null);long startTime = System.currentTimeMillis();for (int i = 0; i < 1000000000; i++) {getName.invoke(user,null);}long endTime = System.currentTimeMillis();System.out.println("02:"+(endTime-startTime)+"ms");}public static void test03() throws ClassNotFoundException, 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("03:"+(endTime-startTime)+"ms");}
}
class User{private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}
// 结果
// 01:4ms
// 02:2792ms
// 03:1514ms

获取泛型参数类型

泛型是给javac做安全检查和避免强制转换的,编译完成就会被擦除。但是为了通过反射操作这些类型,新增了几个class类型外的几个类型:

  • ParameterizedType:参数化类型:Map<String,String>
  • GenericArrayType:数组,存的参数化类型或者类变量
  • TypeVariable:各种类型的父类公共接口
  • WildcardType:通配符类型表达式
    这几种类型不属于class,但是和class同级别

Demo:

public class Demo08 {public static void main(String[] args) throws NoSuchMethodException {Class<? extends Demo08> aClass = Demo08.class;Method mt = aClass.getDeclaredMethod("test", Map.class, List.class,int.class,Demo01.class);Type[] genericParameterTypes = mt.getGenericParameterTypes();// 打印所有参数类型,如果是泛型,打印内部的类类型printActuallyType(genericParameterTypes);// 打印返回值类类型Type genericReturnType = mt.getGenericReturnType();Type[] g={genericReturnType};printActuallyType(g);}public static List<Demo02> test(Map<String, List<Object>> map,List<String> list,int a,Demo01 demo01){return null;}public static void printActuallyType(Type[] t){for (Type type : t) {if(type instanceof ParameterizedType){Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();printActuallyType(actualTypeArguments);}else{System.out.println(type);}}}
}
//控制台输出
//class java.lang.String
//class java.lang.Object
//class java.lang.String
//int
//class com.xiaopi3.Demo01
//class com.xiaopi3.Demo02

通过反射获取注解和注解参数值

这部分比较简单,直接上图:

模拟ORM:先使用注解(这里是自定义了两个注解)标识:

通过反射获取值:

注解和反射复习——B站相关推荐

  1. B站【狂神说Java笔记】-注解和反射

    目录 狂神视频地址 1.什么是注解? 2.内置注解 3.元注解 4.自定义注解 5.Java反射概述 6.Class 类 7.哪些类型可以有Class 对象? 8.类加载与内存分析 9.什么时候会发生 ...

  2. Java学习笔记7-2——注解与反射

    目录 理解 Class 类并获取 Class 实例 Class类 获取 Class 类的实例 哪些类型可以有Class对象 所有类型的Class对象 从内存角度分析类加载[重点] 类加载的过程 什么时 ...

  3. 熬夜刚完的注解与反射

    注解与反射 1.反射的概述 2.反射基本使用 1.获取Class的三种方法 2.通过反射获取构造方法 3.通过反射获取到属性字段 4.通过反射获取方法 3.反射main方法 4.使用反射读取配置文件, ...

  4. Java---->强烈安利0_0详解注解和反射机制

    时刻保持学习之心,方能成就不世功业 注解和反射 1. 注解 1.1 注解概念 注解:Java注解(Annotation)又称Java标注,是JDK5.0之后引入的一种注释机制,它可以标注在类,方法,参 ...

  5. 04Java注解和反射

    Java注解和反射 Java框架的底层即为Java的注解和反射 注解(开胃菜) 注释:给开发人员阅读,不算在程序之内 注解:可以给开发人员阅读,也可以给程序阅读,也可以被其他的程序阅读,也不算在程序之 ...

  6. java 导出excel 注解_Java基于注解和反射导入导出Excel

    list = ei.getDataList(User.class); for (User user : list){ try{ //to do: 保存/处理数据 //userService.save( ...

  7. java 反射 注解 运用_Java注解与反射的使用

    打开 Eclipse,新建 Java 项目"注解与反射",在 src 下右键并建立包 "注解与反射",在包下右键并建立 Annotation (注解)文件,名称 ...

  8. Java基础-注解和反射

    Java基础-注解和反射 前言 对于注解,我主要还是在自定义APT还有运行时反射获取类来让自己能够构建出复用性更高的代码逻辑. 知识点1-注解: 注解的应用场景由元注解@Retention来进行指定, ...

  9. java注解判断字段是否存在_使用注解和反射判断指定的字段不能为空

    我们在写项目的时候,如何类比较少.判别指定对象的属性值是否为空,那确实可以,但是随着类的增多,判别对象的属性是否为空就非常的繁琐,所以可以使用自定义注解和反射来判定指定的字段是否为空. 第一步:创建一 ...

  10. 关于Java你不知道的那些事之Java注解和反射

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:硬刚一周,3W字总结,一年的经验告诉你如何准备校招! 个人原创100W+访问量博客:点击前往,查看更多 作者:轻 ...

最新文章

  1. P4722 【模板】最大流
  2. Leangoo看板协作工具与Trello还真的不一样
  3. resumable oracle,Oracle的Resumable特性
  4. 2018-2019-1 20165206 《信息安全系统设计基础》第九周学习总结
  5. 《Effective STL》学习笔记(第四部分)
  6. post postman 传递数组对象_PostMan Post方式传递数组数据参数 OK_go
  7. 浅谈Spring5 响应式编程
  8. 微型计算机中最小的单位,微型计算机中最小的数据单位是
  9. AI专家告诉你,机器学习与深度学习如何快速进阶?
  10. 886. 求组合数 II(模板)
  11. python语法基础题你好_Python基础要打牢,先学会基本语法
  12. (HDU)1157 -- Who's in the Middle(哪个居中)
  13. react-native 金币彩带雨下落动画
  14. 解决matplotlib中文显示问题
  15. 支付宝疯起来连自己都打
  16. js轮播图 最简单代码
  17. 实时查看MD文件效果 - 在线Markdown预览
  18. Debian权威发音
  19. 如何做好项目规划?以及项目规划常用的管理软件盘点
  20. GSM 07.10 MUX(multiplexer protocol)

热门文章

  1. 【国信安实训】——文件上传漏洞
  2. 计算机未响应怎样解决方案,电脑提示Internet Explorer未响应怎么办?解决IE浏览器未响应的解决方法...
  3. 【洛谷 2504】聪明的猴子
  4. 字节跳动后端开发实习生一面凉经
  5. 分享四款实用流程图模板
  6. Linux进程管理与控制课后作业
  7. 手机用蓝牙键盘好使吗_手机也可以连接键盘,你知道怎么使用吗?
  8. python读取fits第三方库_python读取fits文件
  9. php替换word字符串,word怎么用符号替换字符
  10. 机器学习中的数学——Momentum(Gradient Descent with Momentum, GDM)