Java 注解和反射 - 总结概述

java

注解

什么是注解

  • Annotation是从JDK5.0开始引入的新技术
  • Annotation的作用:

    • 不是程序本身,可以对程序作出解释(这一点和注释(comment)没什么区别)
    • 可以被其他程序(比如:编译器等)读取

  • Annotation的格式:

    • 注解是以“@注释名”在代码中存在的,还可以添加一些参数值,例如:@SuppressWarnings(value="unchecked")

  • Annotation在哪里使用?

    • 可以附加在package,class,method,field等上面,相当于给他们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问


内置注解

  • @Override:定义在java.lang.Override中,此注释只适用于修辞方法,表示一个方法声明打算重写超类中的另一个方法声明
  • @Deprecated:定义在java.lang.Deprecated中,此注释可以用于修饰方法、属性、类,表示不鼓励程序员使用这样的元素,通常是因为它很危险或者存在更好的选择
  • @SuppressWarnings:定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息,与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参数都是已经定义好了的,我们选择性的使用就好了

    • @SuppressWarinings("all")
    • @SuppressWarinings("unchecked")
    • @SuppressWarinings(value={"unchecked","deprecation"})
    • 等等.......

 1 //什么是注解

2 public class Test01 extends Object {

3

4 //@Override 重写的注解

5 @Override

6 public String toString() {

7 return super.toString();

8 }

9

10 //Deprecated 不推荐程序员使用,但是可以使用,或者存在更好的方式

11 @Deprecated

12 public static void test(){

13 System.out.println("Deprecated");

14 }

15

16 //镇压警告

17 @SuppressWarnings("all")

18 public void test02(){

19 List list = new ArrayList();

20 }

21 public static void main(String[] args) {

22 test();

23 }

24 }


元注解

  • 元注解的作用就是负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明
  • 这些类型和它们所支持的类在java.lang.annotation包中可以找到(@Target,@Retention,@Documented,@Inherited)

    • @Target:用来描述注解的使用范围(即:被描述的注解可以用在什么地方)

    • @Retention:表示需要在什么级别保存该注释信息,用来描述注解的生命周期(SOURCE<CLASS<RUNTIME)

    • @Document:说明该注解将被包含在javadoc中
    • @Inherited:说明子类可以继承父类中的该注解

 1 public class Test02 {

2

3 @MyAnnotation

4 public void test(){

5 }

6 }

7

8 //定义一个注解

9 //Target 表示我们的注解可以用在哪些地方:ElementType.METHOD(用在方法上),ElementType.TYPE(可以用在类上)

10 @Target(value = {ElementType.METHOD,ElementType.TYPE})

11

12 //Retention 表示我们的注解在什么地方有效;RUNTIME:运行时,CLASS:编译,SOURCE:源码

13 //runtime>class>source

14 @Retention(value = RetentionPolicy.RUNTIME)

15

16 //Documented 表示是否将我们的注解生成在JavaDoc文档中

17 @Documented

18

19 //Inherited 子类可以继承父类的注解

20 @Inherited

21 @interface MyAnnotation{}


自定义注解

  • 使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
  • 分析:

    • @interface用来声明一个注解,格式:public @interface 注解名{定义内容}
    • 其中的每一个方法实际上是声明了一个配置参数
    • 方法的名称就是参数的名称
    • 返回值类型就是参数的类型(返回值只能是基本类型,Class,String,enum)
    • 可以通过default来声明参数的默认值
    • 如果只有一个参数成员,一般参数名为value
    • 注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0作为默认值

 1 //自定义注解

2 public class Test03 {

3

4 @MyAnnotation02(age = 18,name = "张三")

5 public void test(){}

6

7 @MyAnnotation03("李四")

8 public void test02(){}

9 }

10

11 @Target({ElementType.TYPE,ElementType.METHOD})

12 @Retention(RetentionPolicy.RUNTIME)

13 @interface MyAnnotation02{

14 //注解的参数格式:参数类型 + 参数名();

15 String name() default ""; //default默认该参数为空,使用该注解,此参数不需要必传

16 int age();

17 int id() default -1;//如果默认值为-1,代表不存在

18 String[] schools() default {"北京大学"};

19 }

20

21 @Target({ElementType.TYPE,ElementType.METHOD})

22 @Retention(RetentionPolicy.RUNTIME)

23 @interface MyAnnotation03{

24 String value(); //注解只有一个参数的时候,建议参数名为value,这样使用该注解时,就不需要在输入参数名,直接输入值即可

25 }

反射

静态VS动态语言

动态语言

  • 是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点讲就是在运行时代码可以根据某些条件改变自身结构
  • 主要动态语言:Object-C、C#、JavaScript、PHP、Python等

静态语言

  • 与动态语言相对应的,运行时结构不可变的语言就是静态语言。如:Java、C、C++
  • Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制获得类似动态语言的特性。Java的动态性让编程的时候更加灵活


Java Reflection反射

  • Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
  • Class c = Class.forName("java.lang.String")
  • 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,通过这个镜子看到类的结构,所以,我们形象的称之为:反射

  • Java反射机制提供的功能

    • 在运行时判断任意一个对象所属的类
    • 在运行时构造任意一个类的对象
    • 在运行时判断任意一个类所具有的成员变量和方法
    • 在运行时获取泛型信息
    • 在运行时调用任意一个对象的成员变量和方法
    • 在运行时处理注解
    • 生成动态代理
    • .....

  • Java反射的优点:可以实现动态创建对象和编译,体现出很大的灵活性
  • Java反射的缺点:对性能有影响,使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作
  • 反射相关的主要API

    • java.lang.Class:代表一个类
    • java.lang.reflect.Method:代表类的方法
    • java.lang.reflect.Field:代表类的成员变量
    • java.lang.reflect.Constructor:代表类的构造器
    • .......

 1 //什么叫反射

2 public class Test01 {

3 public static void main(String[] args) throws ClassNotFoundException {

4 //通过反射获取类的class对象

5 Class c1 = Class.forName("reflection.User");

6 System.out.println(c1);

7

8 Class c2 = Class.forName("reflection.User");

9 Class c3 = Class.forName("reflection.User");

10 Class c4 = Class.forName("reflection.User");

11

12 //一个类在内存中只有一个class对象

13 //一个类被加载后,类的整个结构都会被封装在class对象中

14 System.out.println(c2.hashCode());

15 System.out.println(c3.hashCode());

16 System.out.println(c4.hashCode());

17 }

18 }

19

20 //实体类:pojo,entity

21 class User{

22 private String name;

23 private int id;

24 private int age;

25

26 public User() {

27 }

28

29 public User(String name, int id, int age) {

30 this.name = name;

31 this.id = id;

32 this.age = age;

33 }

34

35 @Override

36 public String toString() {

37 return "User{" +

38 "name='" + name + '\'' +

39 ", id=" + id +

40 ", age=" + age +

41 '}';

42 }

43

44 public String getName() {

45 return name;

46 }

47

48 public void setName(String name) {

49 this.name = name;

50 }

51

52 public int getId() {

53 return id;

54 }

55

56 public void setId(int id) {

57 this.id = id;

58 }

59

60 public int getAge() {

61 return age;

62 }

63

64 public void setAge(int age) {

65 this.age = age;

66 }

67 }


得到Class类的几种方式

 1 //测试class类的创建方式有哪些

2 public class Test02 {

3 public static void main(String[] args) throws ClassNotFoundException {

4 Person person = new Student();

5 System.out.println("这个人是:"+person.name);

6

7 //方式一:通过对象获得

8 Class c1 = person.getClass();

9 System.out.println(c1.hashCode());

10

11 //方式二:forname获得

12 Class c2 = Class.forName("reflection.Student");

13 System.out.println(c2.hashCode());

14

15 //方式三:通过类名.class获得

16 Class c3 = Student.class;

17 System.out.println(c3.hashCode());

18

19 //方式四:基本内置类型的包装类都有一个Type属性

20 Class c4 = Integer.TYPE;

21 System.out.println(c4);

22

23 //获得父类类型

24 Class c5 = c1.getSuperclass();

25 System.out.println(c5);

26 }

27 }

28

29 class Person{

30 public String name;

31

32 public Person() {

33 }

34

35 public Person(String name) {

36 this.name = name;

37 }

38

39 @Override

40 public String toString() {

41 return "Person{" +

42 "name='" + name + '\'' +

43 '}';

44 }

45 }

46

47 class Student extends Person{

48 public Student(){

49 this.name="学生";

50 }

51 }

52

53 class Teacher extends Person{

54 public Teacher(){

55 this.name="老师";

56 }

57 }


所有类型的Class对象

 1 //所有类型的class

2 public class Test03 {

3 public static void main(String[] args) {

4 Class c1 = Object.class; //类

5 Class c2 = Comparable.class; //接口

6 Class c3 = String[].class; //一维数组

7 Class c4 = int[][].class;//二维数组

8 Class c5 = Override.class;//注解

9 Class c6 = ElementType.class;//枚举

10 Class c7 = Integer.class;//基本数据类型

11 Class c8 = void.class;//void

12 Class c9 = Class.class;//Class

13

14 System.out.println(c1);

15 System.out.println(c2);

16 System.out.println(c3);

17 System.out.println(c4);

18 System.out.println(c5);

19 System.out.println(c6);

20 System.out.println(c7);

21 System.out.println(c8);

22 System.out.println(c9);

23

24 //只要元素类型与维度一样,就是同一个Class

25 int[] a = new int[10];

26 int[] b = new int[100];

27 System.out.println(a.getClass().hashCode());

28 System.out.println(b.getClass().hashCode());

29 }

30 }


获取类的运行时结构

  1 //反射的作用:获得类的信息

2 public class Test08 {

3 public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {

4 Class c1 = Class.forName("reflection.User");

5

6 //1.获得类的名字

7 System.out.println(c1.getName()); //类名+包名

8 System.out.println(c1.getSimpleName());//类名

9

10 //2.获得类的属性

11 //2.1只能找到public属性

12 Field[] fields = c1.getFields();

13 for(Field f : fields){

14 System.out.println(f);

15 }

16 //2.2可以找到所有属性

17 Field[] fields1 = c1.getDeclaredFields();

18 for(Field f : fields1){

19 System.out.println(f);

20 }

21 //2.3只能找到public的指定属性

22 Field top = c1.getField("top");

23 System.out.println(top);

24 //2.4找到类的指定属性

25 Field name = c1.getDeclaredField("name");

26 System.out.println(name);

27

28 //3.获得类的方法

29 //3.1 获得本类及其父类的全部public方法

30 Method[] methods = c1.getMethods();

31 for (Method method : methods) {

32 System.out.println(method);

33 }

34 //3.2 获得本类的所有方法

35 Method[] declaredMethods = c1.getDeclaredMethods();

36 for (Method declaredMethod : declaredMethods) {

37 System.out.println(declaredMethod);

38 }

39 //3.3 获得指定的方法

40 //获得指定方法一定要加参数,因为牵扯到方法的重载,方法名一样,参数不一样;不传参数,不知道你要获得哪个方法;参数丢类型即可

41 Method getName = c1.getMethod("getName", null);

42 Method setName = c1.getMethod("setName", String.class);

43 System.out.println(getName);

44 System.out.println(setName);

45

46 //4.获得指定的构造器

47 //4.1 获得本类public的构造方法

48 Constructor[] constructors = c1.getConstructors();

49 for (Constructor constructor : constructors) {

50 System.out.println(constructor);

51 }

52 //4.2 获得本类所有的构造方法

53 Constructor[] declaredConstructors = c1.getDeclaredConstructors();

54 for (Constructor declaredConstructor : declaredConstructors) {

55 System.out.println(declaredConstructor);

56 }

57 //4.3 获得指定的构造器

58 Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);

59 System.out.println(declaredConstructor);

60 }

61 }

62

63

64 //实体类:pojo,entity

65 class User{

66 private String name;

67 private int id;

68 private int age;

69

70 public int top=180;

71

72 public User() {

73 }

74

75 public User(String name, int id, int age) {

76 this.name = name;

77 this.id = id;

78 this.age = age;

79 }

80

81 @Override

82 public String toString() {

83 return "User{" +

84 "name='" + name + '\'' +

85 ", id=" + id +

86 ", age=" + age +

87 '}';

88 }

89

90 public String getName() {

91 return name;

92 }

93

94 public void setName(String name) {

95 this.name = name;

96 }

97

98 public int getId() {

99 return id;

100 }

101

102 public void setId(int id) {

103 this.id = id;

104 }

105

106 public int getAge() {

107 return age;

108 }

109

110 public void setAge(int age) {

111 this.age = age;

112 }

113 }


动态创建对象执行方法

 1 //动态的创建对象,通过反射

2 public class Test09 {

3 public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {

4 //获得class对象

5 Class c1 = Class.forName("reflection.User");

6

7 //构造一个对象

8 //User user = (User) c1.newInstance(); //本质上是调用了类的无参构造器。如果类没有无参构造器则会报错

9 //System.out.println(user);

10

11 //如果类没有无参构造器,怎么办?

12 //通过构造器创建对象

13 //Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);

14 //User user1 = (User) constructor.newInstance("张三", 001, 20);

15 //System.out.println(user1);

16

17 //通过反射调用普通方法

18 User user2 = (User) c1.newInstance();

19 //通过反射获取一个方法

20 Method setName = c1.getDeclaredMethod("setName", String.class);

21

22 //invoke:激活的意思

23 //(对象,“方法的值”)

24 setName.invoke(user2,"Gelaotou");

25 System.out.println(user2.getName()); //Gelaotou

26

27 //通过反射操作属性

28 User user3 = (User) c1.newInstance();

29 Field name = c1.getDeclaredField("name");//由于name是private私有属性,所以会报错

30

31 //不能直接操作私有属性,需要关闭程序的安全检测,私有的属性和方法使用setAccessible(true)关闭检测

32 name.setAccessible(true);//关闭程序的安全检测

33

34 name.set(user3,"张三");

35 System.out.println(user3.getName());

36 }

37 }

 1 //性能对比分析

2 public class Test10 {

3

4 //普通方式调用

5 public static void test01(){

6 User user = new User();

7 long startTime=System.currentTimeMillis();

8 for (int i = 0; i < 100000000; i++) {

9 user.getName();

10 }

11

12 long endTime=System.currentTimeMillis();

13 System.out.println("普通方式执行,花费的时间为:"+(endTime-startTime)+"ms");

14 }

15

16 //反射方式调用

17 public static void test02() throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {

18 User user = new User();

19 Class c1 = user.getClass();

20

21 Method getName = c1.getDeclaredMethod("getName",null);

22

23 long startTime=System.currentTimeMillis();

24

25 for (int i = 0; i < 100000000; i++) {

26 getName.invoke(user,null);

27 }

28

29 long endTime=System.currentTimeMillis();

30 System.out.println("反射方式调用执行,花费的时间为:"+(endTime-startTime)+"ms");

31 }

32

33 //反射方式调用 关闭检测

34 public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

35 User user = new User();

36 Class c2 = user.getClass();

37

38

39 Method getName = c2.getDeclaredMethod("getName", null);

40 getName.setAccessible(true);

41

42 long startTime=System.currentTimeMillis();

43

44 for (int i = 0; i < 100000000; i++) {

45 getName.invoke(user,null);

46 }

47

48 long endTime=System.currentTimeMillis();

49 System.out.println("反射方式调用 关闭检测执行,花费的时间为:"+(endTime-startTime)+"ms");

50

51 }

52

53 public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {

54 test01(); //2ms

55 test02(); //216ms

56 test03(); //111ms

57

58 //总结:反射调用过多,关闭检测,可以提高性能

59 }

60 }

类加载内存分析

 1 public class Test05 {

2 public static void main(String[] args) {

3 A a = new A();

4 System.out.println(a.m);

5 /*

6 1.加载到内存,会产生一个类对应class对象

7 2.链接,链接结束后,m=0

8 3.初始化

9 <clinit>(){

10 System.out.println("A类静态代码块初始化");

11 m=300;

12 m=100;

13 }

14 m=100

15 */

16 }

17 }

18

19 class A{

20

21 static {

22 System.out.println("A类静态代码块初始化");

23 m=300;

24 }

25 static int m =100;

26

27 public A() {

28 System.out.println("A类的无参构造初始化");

29 }

30 }

1 //运行结果

2 A类静态代码块初始化

3 A类的无参构造初始化

4 100


分析类的初始化

 1 //测试类什么时候会初始化

2 public class Test06 {

3 static {

4 System.out.println("Test06类静态代码块被加载");

5 }

6

7 public static void main(String[] args) throws ClassNotFoundException {

8 //1.主动引用

9 //Son son = new Son();

10 /*

11 //输出结果:

12 Test06类静态代码块被加载

13 父类静态代码块被加载

14 子类静态代码块被加载

15 */

16

17 //2.反射也会产生主动引用

18 //Class.forName("reflection.Son");

19 /*

20 //输出结果:

21 Test06类静态代码块被加载

22 父类静态代码块被加载

23 子类静态代码块被加载

24 */

25

26 //3.类的被动引用,通过子类调用父类的静态变量,不会导致子类的初始化

27 //System.out.println(Son.b);

28 /*

29 //输出结果,不会导致子类的初始化:

30 Test06类静态代码块被加载

31 父类静态代码块被加载

32 2

33 */

34

35 //4.类的被动引用,通过数组,不会导致类的任何初始化

36 //Son[] array=new Son[5];

37 /*

38 //输出结果:

39 Test06类静态代码块被加载

40 */

41

42 //5.类的被动引用,访问常量,不会导致类的任何初始化

43 System.out.println(Son.n);

44 /*

45 //输出结果:

46 Test06类静态代码块被加载

47 1

48 */

49 }

50 }

51

52 class Father{

53 static int b = 2;

54 static {

55 System.out.println("父类静态代码块被加载");

56 }

57 }

58

59 class Son extends Father{

60 static {

61 System.out.println("子类静态代码块被加载");

62 m=300;

63 }

64

65 static int m=100;

66 static final int n=1;

67 }


类加载器

 1 public class Test07 {

2 public static void main(String[] args) throws ClassNotFoundException {

3 //获取系统类的加载器

4 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();

5 System.out.println(systemClassLoader);

6

7 //获取系统类加载器的父类加载器--->即扩展类加载器

8 ClassLoader parent = systemClassLoader.getParent();

9 System.out.println(parent);

10

11 //获取扩展类加载器的父类加载器--->即根加载器(C、C++)

12 ClassLoader parent1 = parent.getParent();

13 System.out.println(parent1);

14

15 //测试当前类是哪个加载器加载的

16 ClassLoader aClass = Class.forName("reflection.Test07").getClassLoader();

17 System.out.println(aClass);

18 //测试JDK内置的类是谁加载的

19 ClassLoader aClass1 = Class.forName("java.lang.Object").getClassLoader();

20 System.out.println(aClass1);

21

22 //如何获得系统类加载器可以加载的路径

23 System.out.println(System.getProperty("java.class.path"));

24 }

25 }

以上是 Java 注解和反射 - 总结概述 的全部内容, 来源链接: utcz.com/z/391359.html

回到顶部