一,类加载器
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 {
}