0
点赞
收藏
分享

微信扫一扫

类加载器,反射注解

一,类加载器

1,类的加载

-当程序需要使用某个类的时候,如果这个类没有被加载到内存中,

那么系统会通过加载,链接,初始化三个步骤来实现对这个类的初始化。

-加载:

就是把class文件读入到内存中,创建了一个Class对象。

任何类加载到内存的时候都是一个Class对象。

-链接:

验证 看内部结构是否正确,和其他类协调一致 。

准备 给类的成员变量分配空间,给默认值

解析 把类中的二进制数据中的符号引用替换成直接引用。

-初始化:

就是我们之前说过的初始化步骤

2,类的初始化时机

-创建对象的时候

-访问类的静态成员,或者我们给类的静态变量赋值

-调用类的静态方法

-使用反射的方式来创建某个类或者接口对应的class对象

-初始化某个类的子类

-使用java命令运行某个类

3,类加载器 -作用:负责把class文件加载到内存中,生成 class 对象 -我们不需要关心类的加载机制。理解它可以帮助我们更好的理解程序的运行过程。 -组成: 根类加载器 BootstrapClassLoader 负责java中核心类的加载 String System ... 扩展类加载器 ExtensionClassLoader 负责jre中扩展目录中jar包的加载。 应用类加载器 App ClassLoader 负责在jvm启动的时候加载来自java命令class文件。

通过上面这些内容为了让大家了解常用的东西都是谁给我们加载的,以及如何加载的

但是我们必须知道要用一个类(接口)的时候,class文件一定会加载到内存中。

那么我们现在考虑如果我们站在内存中,面对这些内存中的字节码文件,如何使用他们?

这就是反射研究的问题

二,反射

1,java的反射机制指的是在运行状态中,通过字节码文件对象,使用(字节码文件)类中

成员变量,构造方法,成员方法。

-Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意

一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的

成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序

信息以及动态调用对象的功能称为Java语言的反射机制。

-要用反射的方式来使用一个类,必须先获取该类的字节码文件对象,这个字节码

文件对象class对象 就是Class的一个具体对象,我们就可以使用Class类中的方法

来解析class对象中的内容并使用。

2,如何获取字节码文件对象

package com.momo.demo;

import com.momo.entity.Stu;

/*

  • 获取字节码文件对象的方式:
  • Object中的方法:
  • public final Class getClass()
  • 数据类型的静态属性 class
  • Class中的静态方法:
  • static Class forName(String className)
  • 自己玩随意,开发用第三种
  • 因为第三种要的是一个字符串,我们将来就可以吧字符串写入配置文件中。

  • /

public class Demo1 {public static void main(String[] args) throws ClassNotFoundException {Stu s = new Stu();Class c1 = s.getClass();System.out.println(c1);Class c2 = Stu.class;System.out.println(c2);/

Class c4 = int.class;*/

//要给包名+类名

Class c5 = Class.forName("com.momo.entity.Stu");

System.out.println(c5);

System.out.println(c1==c2); System.out.println(c1==c5);

}

}

注意:

在java的世界中万物皆为对象

内存中运行的字节码文件-----Class

成员变量 Field

成员方法 Method

构造方法 Construtor

-Class中的常用方法:

static 类 forName(String className)

返回与给定字符串名称的类或接口相关联的 类对象。

Constructor<T> getConstructor(类<?>... parameterTypes) 返回一个 Constructor对象,该对象反映 Constructor对象表示的类的指定的公共 类函数。 Constructor<?>[] getConstructors() 返回包含一个数组 Constructor对象反射由此表示的类的所有公共构造 类对象。 Constructor<T> getDeclaredConstructor(类<?>... parameterTypes) 返回一个 Constructor对象,该对象反映 Constructor对象表示的类或接口的指定 类函数。 Constructor<?>[] getDeclaredConstructors() 返回一个反映 Constructor对象表示的类声明的所有 Constructor对象的数组 类 。 Field getDeclaredField(String name) 返回一个 Field对象,它反映此表示的类或接口的指定已声明字段 类对象。 Field[] getDeclaredFields() 返回的数组 Field对象反映此表示的类或接口声明的所有字段 类对象。 Field getField(String name) 返回一个 Field对象,它反映此表示的类或接口的指定公共成员字段 类对象。 Field[] getFields() 方法 getDeclaredMethod(String name, 类<?>... parameterTypes) 返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 类对象。 方法[] getDeclaredMethods() 方法 getMethod(String name, 类<?>... parameterTypes) 返回一个 方法对象,它反映此表示的类或接口的指定公共成员方法 类对象。 方法[] getMethods()

3,通过反射获取构造方法并使用

package com.momo.demo;

import com.momo.entity.Stu;

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationTargetException;

//反射获取构造方法对象并使用

/*

  • Constructor getConstructor(Class... parameterTypes)

获取指定参数的公共的构造方法

Constructor getDeclaredConstructor(Class... parameterTypes)

获取指定参数的构造方法,包括私有

参数表示:要获取的构造方法对象的构造参数个数,以及数据类型的class字节码文件对象

Constructor[] getConstructors() 获取所有的公共的构造方法

Constructor[] getDeclaredConstructors() 获取所有的构造方法,包括私有

  • /

public class Demo2 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//获取字节码文件对象Class c = Class.forName("com.momo.entity.Stu");//调用Class的方法获取构造方法对象/

for (Constructor con : cons) {

System.out.println(con);

}//

for (Constructor con : cons) {

System.out.println(con);

}///获取单个构造方法Constructor con = c.getConstructor();//返回的是构造方法对象// System.out.println(con);//使用构造方法创建对象//T newInstance(Object... initargs)//使用Constructor对象所表示的构造方法来创建该构造方法所表示的类的对象Object o = con.newInstance();//new Stu();System.out.println(o);/

Stu s = (Stu)o;

System.out.println(s);*/

}

}

package com.momo.demo;

import com.momo.entity.Stu;

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationTargetException;

/*

  • 使用反射获取构造方法并使用
  • public Stu(String name,int age,String address)
  • 构造方法对象创建对象
  • T newInstance(Object... initargs)
  • /

public class Demo3 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {/

Class c = Class.forName("com.momo.entity.Stu");

//获取指定构造方法对象

Constructor con = c.getConstructor(String.class, int.class, String.class);

//使用构造方法对象中的方法创建对象

Object o = con.newInstance("默默", 18, "长安");

System.out.println(o);*/

/* Class<Stu> c = (Class<Stu>) Class.forName("com.momo.entity.Stu"); Constructor<Stu> con = c.getConstructor(String.class, int.class, String.class); Stu s = con.newInstance("默默", 18, "长安"); System.out.println(s);*/

}

}

package com.momo.demo;

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationTargetException;

/*

  • 使用反射获取构造方法并使用
  • private Stu(String name)
  • */

public class Demo4 {

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

Class c = Class.forName("com.momo.entity.Stu");

//NoSuchMethodException 没有这样方法异常,说明这个方法只能获取公有的

//Constructor con = c.getConstructor(String.class);

Constructor con = c.getDeclaredConstructor(String.class);

//System.out.println(con);

// java.lang.IllegalAccessException 非法访问异常

// 霸王硬上弓,暴力访问。

con.setAccessible(true);//true表示取消访问检查

Object o = con.newInstance("默默");

System.out.println(o);

System.out.println("------------------");

// Constructor con2 = c.getConstructor(String.class, int.class); Constructor con2 = c.getDeclaredConstructor(String.class, int.class); //System.out.println(con2); con2.setAccessible(true); Object o1 = con2.newInstance("aaa", 11); System.out.println(o1);

}

}

-Constructor中的常用方法: T newInstance(Object... initargs) void setAccessible(boolean flag)

4,使用反射获取成员变量并使用

-Field中的常用方法:

Object get(Object obj)

返回该所表示的字段的值 Field ,指定的对象上。

String getName()

返回由此 Field对象表示的字段的名称。

void set(Object obj, Object value)

将指定对象参数上的此 Field对象表示的字段设置为指定的新值。

.......

public void setAccessible(boolean flag)

package com.momo.demo;

import com.momo.entity.Stu;

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.InvocationTargetException;

/*

  • 反射获取成员变量并使用
  • Field[] getFields()
  • Field[] getDeclaredFields()
  • Field getField(String name)
  • Field getDeclaredField(String name)
  • */

public class Demo5 {

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

Class c = Class.forName("com.momo.entity.Stu");

/* Field[] fs = c.getFields(); for (Field f : fs) { System.out.println(f); }*/

/* Field[] fs = c.getDeclaredFields();

for (Field f : fs) {

System.out.println(f);

}*/

//获取单个成员变量对象 (成员变量: 赋值 获取) Field f = c.getField("address");//成员变量对象 //赋值void set(Object obj, Object value) //第一个参数是对象,第二个参数是值。 表示要给哪个对象的这个成员变量赋什么值 //给成员变量赋值前,需要创建对象出来,给指定对象的成员变量赋值 Constructor con = c.getConstructor(); Object o = con.newInstance(); System.out.println(o); f.set(o,"长安");//给o这个对象的f成员变量赋值 长安 System.out.println(o); System.out.println("-------------"); //获取name赋值 // java.lang.NoSuchFieldException // Field name = c.getField("name"); Field name = c.getDeclaredField("name"); //java.lang.IllegalAccessException //取消访问检查 name.setAccessible(true); name.set(o,"momo"); System.out.println(o); System.out.println("------------"); //获取age赋值 Field age = c.getDeclaredField("age"); age.setAccessible(true); age.set(o,18); System.out.println(o); System.out.println("---------------"); Object aa = age.get(o); System.out.println(aa);

}

}

5,使用反射获取成员方法并使用

-Method中的常用方法:

String getName()

返回由此 方法对象表示的方法的名称,作为 String 。

int getParameterCount()

返回由此对象表示的可执行文件的形式参数(无论是显式声明还是隐式声明)的数量。

Object invoke(Object obj, Object... args)

在具有指定参数的 方法对象上调用此 方法对象表示的底层方法。

public void setAccessible(boolean flag)

package com.momo.demo;

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

/*

  • 使用反射获取成员方法并使用
  • Method getDeclaredMethod(String name, 类... parameterTypes)

Method[] getDeclaredMethods()

只能获取子类中的所有方法,包括私有

Method getMethod(String name, 类... parameterTypes)

Method[] getMethods()

  • 获取所有公共方法,包括父类中的
  • /

public class Demo6 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Class c = Class.forName("com.momo.entity.Stu");/

for (Method method : methods) {

System.out.println(method);

}*/

/* Method[] methods = c.getDeclaredMethods(); for (Method method : methods) { System.out.println(method); }*/ //获取show Method m = c.getMethod("show");//获取的是成员方法对象 Constructor con = c.getConstructor(); Object o = con.newInstance(); //o.m(); //Object invoke(Object obj, Object... args) Object obj = m.invoke(o);// // System.out.println(obj); System.out.println("------------------"); //void method(String s) Method m2 = c.getMethod("method", String.class); m2.invoke(o,"asdfdsf"); System.out.println("------------------"); //String get(String s,int i) Method m3 = c.getMethod("get", String.class, int.class); Object o3 = m3.invoke(o, "123", 456); System.out.println(o3); System.out.println("------------------"); // private void fun() Method m4 = c.getDeclaredMethod("fun"); m4.setAccessible(true); m4.invoke(o); System.out.println("------------------");

}

}

三,注解

1,概述

-说明程序,给计算机看的。在程序执行中起到一定的作用。

-注释:解释程序的文字,给程序员看的。

-注解也就是Annotation,也叫元数据,是一种代码级别的说明。

和类,接口是一个级别的。

它可以声明在包,类,字段,方法,等上面,用来对这些元素进行说明

2,作用

-编写文档:通过代码中标识的注解生成文档

-代码分析:通过代码中标识的注解对代码进行分析

-编译检查:通过代码中标识的注解可以让编译器实现基本的编译检查

-主要作用是在框架中应用,替换部分配置文件。

3,定义格式

-@interface 注解名{}

-作用:

编译检查

替换配置文件

定义注解:元注解(注解上的注解)

分析代码

4,java中的几个注解

-@Override 标识方法是从父类继承过来的。 执行编译检查

-@SuppressWarnings("all") 抑制警告 all表示所有

-@Deprecated 表示方法以过时,不建议使用。

-@FunctionalInterface 接口上用,表示是一个函数式接口。

package com.momo.demo;

import com.momo.entity.Stu;

import java.util.Date;

public class Demo7 {

public static void main(String[] args) {

// new Date().toLocaleString();

Stu s = new Stu();

String ss = s.get("aaa", 123);

System.out.println(ss);

}

}

package com.momo.entity;

@SuppressWarnings("all")

public class Stu {

private String name;

int age;

public String address;

public Stu(){}

// Stu(){}

private Stu(String name){

this.name = name;

}

Stu(String name,int age){ this.name = name; this.age = age; } public Stu(String name,int age,String address){ this.name = name; this.age = age; this.address = address; } public void show(){ System.out.println("show"); } public void method(String s){ System.out.println("method"+s); } @Deprecated public String get(String s,int i){ return s+i; } private void fun(){ System.out.println("fun"); } @Override public String toString() { return "Stu{" + "name='" + name + '\'' + ", age=" + age + ", address='" + address + '\'' + '}'; }

}

5,自定义注解

-格式:@interface 注解名{}

-注解属性:

注解当成一个接口,接口中可以有常量和抽象方法

抽象方法在注解中就叫做注解属性

基本类型 String Class Annotation 枚举 以上类型的数组

-注意:注解中一旦有了注解属性,使用注解的时候就必须给属性赋值

(除非这个注解有默认值)

package com.momo.demo;

import com.momo.entity.Stu;

import java.util.Date;

public @interface MyAnnotation {

//注解属性

int i();

String s();

//Date d(); String[] strs(); Class c(); aaa a();

// Stu s(); Food BAOZI(); }

package com.momo.demo;

import com.momo.entity.Stu;

import java.util.Date;

/@MyAnnotation3(i = 123)/

/@MyAnnotation3(value = 123)/

/@MyAnnotation3(123)/

/@MyAnnotation3(s = "123")/

@MyAnnotation3(ss = {"aaa","bbb"})

public class Demo7 {

public static void main(String[] args) {

// new Date().toLocaleString();

Stu s = new Stu();

String ss = s.get("aaa", 123);

System.out.println(ss);

}

}

package com.momo.demo;

public @interface MyAnnotation3 { /int i();/ /* int value();/ / String s();*/ String[] ss(); }

-赋值的格式: @注解名(属性名=值) 注解属性是数组,如果只有一个值: 属性名=值 属性名={值} 如果有多个值: 属性名={值1,值2,...} 如果属性名叫value,并且只需要给这个value赋值的时候,value名字可以不写。

6,元注解

-定义在注解上的注解

-@Retention 规定注解保留到什么阶段,值是RetentionPolicy里面的三个枚举值

RetentionPolicy.SOURCE-----只在代码中保留,在字节码文件中删除

RetentionPolicy.CLASS -----在代码和字节码中保留

RetentionPolicy.RUNTIME ----所有阶段都保留

-@Target 规定注解用于什么地方,取值在枚举类 ElemenetType 中:

ElemenetType.CONSTRUCTOR-----构造器声明

ElemenetType.FIELD -----域声明(包括 enum 实例)

ElemenetType.LOCAL_VARIABLE-----局部变量声明

ElemenetType.METHOD -----方法声明

ElemenetType.PACKAGE -----包声明

ElemenetType.PARAMETER ---参数声明

ElemenetType.TYPE----类,接口(包括注解类型)或enum声明

package com.momo.demo;

import com.momo.entity.MyAnnotation4;

/@MyAnnotation4/

public class Demo8 {

/* @MyAnnotation4*/

int a;

@MyAnnotation4

public void add(){}

}

package com.momo.entity;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface MyAnnotation4 { }

7,练习:自定义注解,模拟juint测试 @Test

-自定义一个注解 @MyTest 在另一个方法上加上这个注解,这个方法就可以执行。

反射

package com.momo.demo;

import com.momo.entity.MyTest;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

public class Demo9 {

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

Class c = Class.forName("com.momo.entity.Tea");

Method[] methods = c.getMethods();

for (Method m : methods) {

boolean boo = m.isAnnotationPresent(MyTest.class);

if(boo){

m.invoke(c.newInstance());

}

}

}

}

package com.momo.entity;

public class Tea {

@MyTest

public void fun1(){

System.out.println("fun1执行了");

}

public void fun2(){ System.out.println("fun2执行了"); }

}

package com.momo.entity;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface MyTest {

}

举报

相关推荐

0 条评论