注解,反射,类加载内存方式,反射操作注解
注解的简介
什么是注解Annotation
- 不是程序本身,可以对程序做出解释
- 可以被其他程序读取
Annotation的格式
@注释名
例:@Override
Annotation在哪里使用
可以附加在package,class,method,field上面,相当于给他们添加了额外的辅助信息
我们可以通过反射机制编程实现对这些元数据的访问
内置注解
-
@Override:表示一个方法声明打算重写超类中的另一个方法声明
-
@Deprecated:表示不鼓励程序员使用这个的元素,通常是因为它很危险或者存在更好的选择
-
@SupperessWarnings:用来抑制编译时的警告信息,必须添加一个参数才能正常使用
@SupperessWarnings(“all”)
元注解
元注解负责注解其他注解,被用来提供对其他annotation类型作说明
类型:meta-annotation
- @Target:用于描述注解的适用范围:注解可以用在什么地方
- @Retention:需要在什么级别保存该注释信息,描述注解的生命周期(SOUCRE<CLASS<RUNTIME),一般使用RUNTIME
- @Document:说明该注解将被包含在javadoc中
- @Inherited:说明子类可以继承父类的注解
反射
动态语言:运行时可以改变其结构的语言,运行时代码可以根据某些条件改变自身结构
静态语言:运行时结构不可变
定义
反射Reflection,反射机制运行程序在执行期借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象的内部属性及方法.
Class c =Class.forName("java.lang.String");
加载完类后,在堆内存的方法去产生一个Class类型的对象,这个对象包含了完整的类的结构信息.
一个类在内存中只有一个Class对象
一个类呗加载后,类的整个结构会被封装在Class对象中
获得对象的方式
正常方式:引入包->通过new实例化->取得实例化对象
反射方式:实例化对象->getClass方法->得到完整的包类名称
public static void main(String[] args) {
try {
Class user = Class.forName("User");
System.out.println(user);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
源码分析
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)
throws ClassNotFoundException;
在object类中,定义了getclass方法,此方法会被所有子类继承
public final native Class<?> getClass();
Class类
通过反射可以得到某个类的属性,方法和构造器.某个类到底实现了那些借口.
对于每个类而言,JRE为其保留一个不变的Class类型对象.
- Class本身也是一个类
- Class对象只能由系统建立对象
- 一个加载的类在JVM中只有一个Class实例
- 一个Class对象对应的是一个加载到JVM的一个.class文件
- 每个类的实例都会记得自己是由哪个Class实例所生成
- 通过Class可以完整地得到一个类中的所有被加载的结构
常用方法
public static Class<?> forName(String className) //获取指定类名的Class对象
public T newInstance() Object newInstance() //调用缺省构造函数,返回Class对象的一个实例
public String getName() { //返回Class所代表的的实体的名称
public native Class<? super T> getSuperclass(); //返回当前Class对象的父类的Class对象
public Class<?>[] getInterfaces() { //获取当前Class对象的接口,接口可能不止一个
public ClassLoader getClassLoader() { //返回该类的类加载器
public Constructor<?>[] getConstructors() throws SecurityException { //返回一个包含某些Constructor 对象的数组
public Method getMethod(String name, Class<?>... parameterTypes) //返回一个Method对象,对象的形参类型为paramType
public Field[] getDeclaredFields() throws SecurityException { //返回Field对象的一个数组
源码分析
public static Class<?> forName(String className) //获取指定类名的Class对象
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
public T newInstance() Object newInstance() //调用缺省构造函数,返回Class对象的一个实例
public String getName() { //返回Class所代表的的实体的名称
String name = this.name;
if (name == null)
this.name = name = getName0();
return name;
}
public native Class<? super T> getSuperclass(); //返回当前Class对象的父类的Class对象
public Class<?>[] getInterfaces() { //获取当前Class对象的接口,接口可能不止一个
ReflectionData<T> rd = reflectionData();
if (rd == null) {
// no cloning required
return getInterfaces0();
} else {
Class<?>[] interfaces = rd.interfaces;
if (interfaces == null) {
interfaces = getInterfaces0();
rd.interfaces = interfaces;
}
// defensively copy before handing over to user code
return interfaces.clone();
}
}
public ClassLoader getClassLoader() { //返回该类的类加载器
ClassLoader cl = getClassLoader0();
if (cl == null)
return null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());
}
return cl;
}
public Constructor<?>[] getConstructors() throws SecurityException { //返回一个包含某些Constructor 对象的数组
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
return copyConstructors(privateGetDeclaredConstructors(true));
}
public Method getMethod(String name, Class<?>... parameterTypes) //返回一个Method对象,对象的形参类型为paramType
throws NoSuchMethodException, SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
Method method = getMethod0(name, parameterTypes, true);
if (method == null) {
throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
}
return method;
}
public Field[] getDeclaredFields() throws SecurityException { //返回Field对象的一个数组
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
return copyFields(privateGetDeclaredFields(false));
}
获取Class对象的实例
- 已知具体的类,通过类的Class属性获取 Class person = Person.class;
- 已知某个类的实例,调用该实例的getClass()方法获取Class对象 Person person = new Person(); Class personclass = person.getClass();
- 已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取
- 内置基本数据类型可以直接用类名.Type
所有类型的Class对象
类,接口,注解,void,数组
类加载内存方式
- 堆:存放new的对象和数组,可以被所有的线程共享,不会存放别人对象引用
- 栈:存放基本变量类型,包含这个基本类型的具体数值和引用对象的变量(存放这个引用在对立面的具体地址)
- 方法区:可以被所有的线程共享,包含了所有的class和static变量
类的加载过程
当程序主动使用某个类时,如果该类未被加载到内存中,系统会通过三个步骤对该类进行初始化
-
类的加载:将类的class文件读入内存,并创建一个java.lang.Class对象,由类加载器完成
将class文件字节码加载到内存中
-
类的链接:将类的二进制数据合并到JRE中
验证:确保加载的类符合JVM规范,没有安全方面的问题
准备:为类变量static分配内存并设置类变量默认初始值的阶段,这些内存将在方法区中进行分配
解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程
-
类的初始化:JVM负责对类进行初始化
- 执行类构造器方法的过程
- 初始化一个类时,若父类未初始化,则先出法对父类的初始化
- 虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步
-
类的初始化
类的主动引用(一定会发生类的初始化)
- 虚拟机启动,先初始化main方法所在的类
- new一个类的对象
- 调用类的静态成员(除了final常量)和静态方法
- 使用java.lang.reflect包方法对类进行反射调用
- 初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
类的被动引用(不会发生类的初始化)
- 访问一个静态域时,只有真正声明这个域的类才会被初始化.通过子类引用父类的静态变量,不会导致子类的初始化
- 通过数组定义类引用,不会触发此类的初始化
- 引用常量不会触发此类的初始化
类加载器的作用
将class文件字节码内容加载到内存中,并将这些静态数据转换成方法去的运行时数据结构,然后在堆重生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口
类缓存:标准的JavaSer类加载器可以按要求寻找类,一旦某个类被加载到类加载器中,它将维持加载缓存一段时间,jvm垃圾回收机制可以回收这些Class对象
分类
- 引导类加载器,用c++编写,JVM自带的类加载器,负责Java平台核心库,用来装载核心类库,该加载器无法直接获取
- 扩展类加载器:负责jre/lib/ext目录下的jar包 或-D java.ext.dirs指定目录下的jar包装入工作库
- 系统类加载器:负责java -classpath或 -D java.class.path所指的目录下的类与jar包装入工作
public class Classloader { //获取一个系统类的加载器
public static void main(String[] args) {
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
System.out.println(systemClassLoader.getParent()); //获取父类 扩展类加载器
System.out.println(systemClassLoader.getParent().getParent()); //获取根加载器
}
}
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@372f7a8d
null //根加载器为C++ 无法读取
//获取当前类是哪个加载器加载的
try {
System.out.println(Class.forName("Classloader").getClassLoader());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
sun.misc.Launcher$AppClassLoader@18b4aac2 //由系统类加载器加载
//获得系统类的可以加载的路径
System.out.println(System.getProperty("java.class.path"));
创建运行时类的对象
获取运行时类的完整结构
//获得类的名字
System.out.println(classloader.getName()); //获得包名+类名
System.out.println(classloader.getSimpleName()); //获得类名
//获得类的属性
Field[] fields = classloader.getFields(); //只能获取public属性
fields = classloader.getDeclaredFields(); //获取全部的属性 包括 private
for (Field field: fields)
{
System.out.println(field);
}
Method[] methods = classloader.getMethods(); //获得本类和父类的全部public方法
Method[] declaredMethods = classloader.getDeclaredMethods();//获得本类的所有方法
//获得指定方法
Method getName = classloader.getMethod("getName", null);
Method setName = classloader.getMethod("setName", String.class);
System.out.println(getName);
System.out.println(setName);
动态创建对象执行方法
创建类的对象,使用Class对象的newInstance方法
-
类必须有一个无参数的构造器
-
类的构造器访问权限需要足够
//获得Class对象 Class<?> classloader = Class.forName("Classloader"); /* 构造对象 本质调用无参构造器 */ Classloader o = (Classloader) classloader.newInstance();
若没有无参构造器,则操作的时候需要明确的调用类中的构造器,并将参数传递进去之后,才可以实例化操作
- 通过Class类的getDeclaredConstructor取得本类的指定形参类型的构造器
- 向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数
- 通过Constructor实例化对象
/* 通过构造器创造对象 */
Constructor<?> declaredConstructor = classloader.getDeclaredConstructor(int.class, String.class);
Classloader o1 = (Classloader) declaredConstructor.newInstance(5, "100");
//通过反射调用普通方法
//invoke 激活了 传递一个对象
Method setName = classloader.getDeclaredMethod("setName", String.class);
setName.invoke(o,"Lyc");
System.out.println(o.getName());
//通过反射操作属性
Classloader o2 = (Classloader) classloader.newInstance();
Field name = classloader.getDeclaredField("name");
name.setAccessible(true);
name.set(o2,"lyc2");
获取注解信息,反射操作注解
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class aClass = Class.forName("Student");
//通过反射获得注解
for (Annotation annotation : aClass.getAnnotations()) {
System.out.println(annotation);
}
//获得注解value的值
Table annotation = (Table) aClass.getAnnotation(Student.class);
System.out.println(annotation.value());
//获得类指定的注解
Field name = aClass.getDeclaredField("name");
Field1 annotation1 = name.getAnnotation(Field1.class);
System.out.println(annotation1.columnName());
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Field1{
String columnName();
String type();
int length();
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Field1{
String columnName();
String type();
int length();
}