一、类加载
时机:
创建对象的实例
调用该类的静态方法
使用反射方式强制创建某类或者接口的java.lang.Class对象
初始化某个子类
直接使用java.exe命令运行某个主类
二、类加载器
1.概述: 负责将Class文件加载到内存中,并为之生成对应的Class对象
把Hello.class字节码文件中Hello类加载到内存的过程
java Hello就会触发java类加载
2.分类:
①.启动类加载器 /jre/lib/rt.jar JAVA核心类加载
②.扩展类加载器 jre/lib/ext/.jar JRE中jar包,JDK中JRE的lib目录下的ext目录
③.本地类加载 classpath:. java命令的class文件,classpath环境变量所指的jar包,类路径
为了避免类的重复加载
3.双亲委托机制:
①.执行java Hello命令时候开始类加载(得到加载类的指令)
②.本地类加载器接到加载Hello类的指令,但是不做处理,反馈给上级扩展类加载器
③.扩展类加载器得到加载Hello类的指令,但是也不做处理,反馈给上级启动类加载器
④.启动类加载器得到加载Hello类的指令,直接处理,进行类加载。加载rt.jar中的类,但是
没有加载到Hello的类,接着启动类加载器又把加载 Hello类的指令向下交给扩展类加载器进行完成
⑤.扩展类加载器得到上级分配的任务:加载HelloWorld类,立刻加载jre/lib/ext/*.jar,但是
也没有加载到Hello的类,接着扩展类加载器又把加载Hello类的指向下交给本地类加载器进行完成。
⑥.本地类加载器得到上级分配的任务:加载Hello类,立刻执行加载ClassPath下的类,如果
加载到了Hello类,调用main方法执行,如果没有加载到Hello类就报异常,ClassNotFindException
类找不到。
三、反射
1.概述: 利用类加载时在堆中创建的java.lang.Class对象去获得该类加载以后在方法区中
创建的类信息,方法信息,变量信息…(一个对象获取自身的Class对象的过程)
2.作用: 可以帮你获取指定类的细节对象
3.获取字节码对象的方式:
①.Class.forName(“全限定名=包名+类名”)
②.类名.Class
③.对象.getClass()
利用该类的Class对象可以创建对象,访问属性,访问方法,访问构造器
4.反射对象的创建
自己不能创建,是由JVM在执行完类加载后会给加载器类创建它的镜像,因为类只
加载一次,所以任意类的Class对象在内存中只有一个
反射创建对象的两种方式:
①.直接用class.newInstance();//调用无参构造器创建对象
②.利用class获得有参构造器,然后调用newInstance(参数…);
5.细节对象
①.构造器
newInstance 调用无参构造器,必须存在public构造器
clazz.getConstructors() 获取所有public构造器
clazz.getDeclaredConstructors()获取所有构造器包括私有
clazz.getConstructor(Class…paraTypes) 获取指定公有构造器
clazz.getDeclaredConstructor(Class…paraTypes) 可获取指定私有构造器
②.通过成员变量
clazz.getFields() 获取可见成员变量
clazz.getDeclaredFields() 获取所有成员变量(私有)
clazz.getField("") 获取指定可见成员变量
clazz.getDeclaredField("") 获取指定成员变量(私有)
③.方法
Class.getMethod(String,Class…paraTypes) 获取类中所有公有方法
Class.getDeclaredMethod(String,Class…paraTyoes) 获取类中所有方法(私有)
invoke(Object,Object…args) 调用该方法(赋值)
④.注解
getDeclaredAnnotations();或者getAnnotations();
method.getAnnotations();或
method.getDeclaredAnnotations(); 获取方法上的注解
field.getAnnotations();或
field.getDeclaredAnnotations(); 获取属性上的注解
四、注解
@Target
表示注解能写在什么上面,作用于哪里。
METHOD 可用于方法上
TYPE 可用于类或者接口上
FIELD 可用于属性上
PARAMETER 可用于参数上
CONSTRUCTOR 可用于构造方法上
ANNOTATION_TYPE 可用于注解类型上(被@interface修饰的类型)
LOCAL_VARIABLE 可用于局部变量上
PACKAGE 用于记录java文件的package信息
@Retention 保留
定义了该Annotation被保留的时间长短
1,仅出现在源代码中,而被编译器丢弃
2,被编译在class文件中
1.SOURCE:在源文件中有效(即源文件保留)
2.CLASS:在class文件中有效(即class保留)
3.RUNTIME:在运行时有效(即运行时保留)
@Documented 文档API
annotation应该被作为被标注的程序成员的公共API
@Inherited 被继承的
@Inherited阐述了某个被标注的类型是被继承的
@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类
自定义注解:
public @interface A {}
给注解定义属性:
权限 参数 属性名 默认 值
public String value() default “”;
注:权限只有public 和 默认的
参数支持的数据类型:
基本数据类型
String类型
Class类型,可以添加泛型
以及上面的数组类型
反射:
通过反射实例化User对象.
class User{
private int id;//id号
private String name; //用户名
private String password;//密码
//构造器和相应的set,get方法
public boolean checkName(String name){//实现代码}
public User getName(String name){//实现代码}
}
a)查询API查询该User对象包含哪些属性,属性的名字,访问修饰符等信息。
修改某个属性的值,获取某个属性的值。
b)查询API查询该User对象包含哪些方法,方法的名字,访问修饰符等信息。
通过反射调用某个方法。
c)查询API查询该User对象包含哪些构造器,构造器的名字,访问修饰符等信息。
通过反射调用构造器。
User类
package com.briup.day12;
public class User{
private int id;//id号
private String name; //用户名
private String password;//密码
private User user;
public User() {
super();
}
protected User(int id, String name, String password) {
super();
this.id = id;
this.name = name;
this.password = password;
}
//构造器和相应的set,get方法
public boolean checkName(String name){
return false;
}
public User getName(String name){
user=new User(1, name, "123");
return user;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", password=" + password
+ ", user=" + user + "]";
}
}
UserTest类
package com.briup.day12;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import javax.swing.plaf.synth.SynthSeparatorUI;
public class UserTest {
public static void main(String[] args) throws ClassNotFoundException {
//获取class对象
try {
//镜像
Class<?> class1 = Class.forName("com.briup.day12.User");
Object instance = class1.newInstance();
//获得所有成员变量(私有)
Field[] fields = class1.getDeclaredFields();
for(Field f:fields) {
//获得属性的访问修饰符
int modifiers = f.getModifiers();
//获得属性的类型
Class<?> type = f.getType();
//获得属性的名字
String name = f.getName();
System.out.println(modifiers+" "+type+" "+name);
}
//获得指定成员变量(私有)
Field field = class1.getDeclaredField("name");
//通过反射修改某个属性的值,获取某个属性的值。
field.setAccessible(true);//私有属性需要设置可见性
field.set(instance, "zhangsan");
Method[] methods = class1.getDeclaredMethods();
for(Method m:methods) {
//获得方法访问修饰符
int modifiers = m.getModifiers();
//获得方法的返回类型
Class<?> type = m.getReturnType();
//获得方法的名字
String name = m.getName();
//获得方法的参数类型
Class<?>[] parameterTypes = m.getParameterTypes();
System.out.println(modifiers+" "+type+" "+name+"("+parameterTypes+")"+parameterTypes.length);
}
//通过反射调用某个方法
Method method = class1.getDeclaredMethod("getName", String.class);
User user = (User)method.invoke(instance,"Lucy");
Constructor<?>[] constructors = class1.getDeclaredConstructors();
for(Constructor c:constructors) {
int modifiers = c.getModifiers();
String name = c.getName();
Class[] types = c.getParameterTypes();
System.out.println(modifiers+" "+name+"("+types+")");
}
//通过反射调用构造器
Constructor<?> constructor = class1.getDeclaredConstructor(int.class,String.class,String.class);
System.out.println(constructor.newInstance(3,"wangwu","123456"));
}catch(Exception e) {
e.printStackTrace();
}
}
}