文章目录
一、反射
1. 反射概述(Class/Field/Method/Constructor)
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Java基础篇:反射机制详解
实际上,我们创建的每一个类也都是对象,即类本身是java.lang.Class类的实例对象。这个实例对象称之为类对象,也就是Class对象。
通俗的说,所有的类都可以通过Class类进行反射操作,可以视Class类为类的母类,其包含所有类的实例方法,实例对象等。
2. 获取Class类的对象
我们要向通过反射去使用一个类,首先我们要获取到该类的字节码文件对象,也就是类型为Class类型的对象,可以通过以下三种方法来获取Class类型的对象。
- 使用class属性来获取该类对应的Class对象。比如:Student.class将会返回Student类对应的Class对象
- 调用对象的getClass()方法,返回该对象所属类的对应的Class对象(该方法是Object类中的方法,返回该对象所属类对应的Class对象)
- 使用Class类中的静态方法forName(String className),该方法需要传入字符串参数,该字符串参数的值是某个类的全路径,也就是完整包名的路径。
Class.forName()(常用)
Hero.class
new Hero().getClass()
3. 反射获取构造方法并使用
Class类中用于获取构造方法的方法
Constructor<?> [] getConstructors():返回所有公共构造方法对象的数组
Constructor<?> []getDeclaredConstructors():返回所有构造方法对象的数组
Constructor []getConstructor(Class<?>…parameterTypes):返回单个公共构造方法对象
Constructor[] getDeclaredConstructor(Class<?>…parameterTypes):返回单个构造方法对象
代码示例:
import java.util.Date;
public class Student {
private int age;
public String name;
public static Date time;
public Student(){}
public Student(String name){
this.name = name;
System.out.println ("name:"+name);
}
public Student(String name,int age){
System.out.println ("name:"+name+","+"age:"+age);
}
private Student(int age){
System.out.println ("age:"+age);
}
}
package com.Reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
Class<?> c1 = Class.forName ( "com.Reflect.Student" );//代表Student类在内存中的字节码对象
System.out.println ( c1 );
System.out.println ( "----------" );
Constructor<?> cons = c1.getConstructor ( String.class );//得到Student类的构造方法,可以创建对象
Object obj = cons.newInstance ( "bob" );//创建实例对象
System.out.println ( obj );
Class<Student> c2 = Student.class;
System.out.println ( c2 == c1 );
Constructor<Student> dc = c2.getDeclaredConstructor ( String.class );
dc.setAccessible ( true );//暴力反射
dc.newInstance ( "dvv" );
System.out.println ("---------------");
Constructor<?>[] dc2 = c2.getDeclaredConstructors ( );
for (Constructor con :dc2){
System.out.println (con);
}
System.out.println ("----------");
Student obj1 = dc.newInstance ( "david" );
System.out.println (obj1);
Student s1 = new Student ();
Class<? extends Student> c3 = s1.getClass ();//
System.out.println ( c3 == c2 );
}
}
class com.Reflect.Student
----------
name:bob
com.Reflect.Student@38af3868
true
name:dvv
---------------
private com.Reflect.Student(int)
public com.Reflect.Student(java.lang.String,int)
public com.Reflect.Student(java.lang.String)
public com.Reflect.Student()
----------
name:david
com.Reflect.Student@1218025c
true
4. 获取成员方法并调用
Method[] getMethod():返回所有公共成员方法对象的数组,包括继承的 Method[] getDeclareMethod():返回所有成员方法对象的数组,不包括继承的 Method getMethod(String name,Class<?>...parameter Types):返回单个公共成员方法对象 Method getDeclareMethod(String name,Class<?>...parameter Types):返回单个成员方法对象
Method类中调用成员方法的方法
Object invoke(Object obj,Object...args):调用obj对象的成员方法,参数是args,返回值是Object类型
demo:
package com.Reflect;
import java.util.Date;
public class Student {
private int age;
public String name;
public static Date time;
public Student(){}
public Student(String name){
this.name = name;
System.out.println ("name:"+name);
}
public Student(String name,int age){
System.out.println ("name:"+name+","+"age:"+age);
}
private Student(int age){
System.out.println ("age:"+age);
}
public void m1(){}
public void m2(String name){
System.out.println (name );
}
public void m3(String name,int age){
System.out.println (name+":"+age);
}
public void m4(Date d){
System.out.println (d);
}
public static void m5(){
System.out.println ("m5");
}
public static void m6(String[] strs){
System.out.println (strs.length);
}
public static void main(String[] args) {
System.out.println ("main");
}
}
package com.Reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectDemo1 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> c1 = Class.forName ( "com.Reflect.Student" );
Object obj = (Student)c1.newInstance ();
Method m1 = c1.getMethod ( "m1", null );
m1.invoke ( obj,null );
Class<Student> c2 = Student.class;
Student ins = c2.newInstance ();
Method m2 = c2.getMethod ( "m2", String.class );
m2.invoke ( ins,"bob" );
Method m3 = c2.getDeclaredMethod ( "m3",String.class,int.class );
m3.invoke ( ins,"david",10 );
}
}
二、注解
2.1 创建注解
定义注解与定义接口有点类似,都用了interface,不过注解前多了@。
此外,包含两个元注解@Target和@Retention,这两个注解专门用于定义注解本身。@Target表示注解的目标,@Override的目标是方法(ElementType.METHOD)。ElementType是一个枚举,主要可选值包含:
demo
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class InheritDemo {
@Inherited
@Retention ( RetentionPolicy.RUNTIME )
static @interface Test{
}
@Test
static class Base{}
static class Child extends Base{}
public static void main(String[] args) {
System.out.println (Child.class.isAnnotationPresent ( Test.class ));
}
}
运行结果:
true
2.2 查看注解信息
主要考虑@Retrntion为RetentionPolicy.RUNTIME的注解,利用反射机制在运行时进行查看和利用这些信息
//获取所有的注解
public Annotation[] getAnnotations();
//获取所有本元素上直接声明的注释,忽略inherited来的
public Annotation[] getDeclaredAnnotations();
//获取指定类型的注解,没有返回null
public <A extends Annotation> A getAnnotation(Class<A> annotationClass);
//判断是否有指定类型的注解
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);
public interface Annotation{
boolean equals(Object obj);
int hashCode();
String toString();
//返回真正的注解类型
Class<?extends Annotation> annotationType();
}
//对于Method和Contructor,它们都有方法参数,而参数也可以注解,都有方法:
public Annotation[] getParameterAnnotations();
demo
import java.lang.annotation.*;
import java.lang.reflect.Method;
public class MethodAnnotations {
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
static @interface QueryParam {
String value();
}
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
static @interface DefaultValue {
String value() default " ";
}
public void hello(@QueryParam("action") String action,
@QueryParam("sort") @DefaultValue("asc") String sort) {
//..
}
public static void main(String[] args) throws NoSuchMethodException {
Class<MethodAnnotations> cls = MethodAnnotations.class;
Method method = cls.getMethod ( "hello", String.class, String.class );
Annotation[][] annts = method.getParameterAnnotations ();
for (int i = 0; i < annts.length; i++) {
System.out.println ( "annotation for parameter" + (i + 1) );
Annotation[] anntArr = annts[i];
for (Annotation annt : anntArr) {
if (annt instanceof QueryParam) {
QueryParam qp = (QueryParam) annt;
System.out.println ( qp.annotationType ()
.getSimpleName () + ":" + qp.value () );
} else if (annt instanceof DefaultValue) {
DefaultValue dv = (DefaultValue) annt;
System.out.println ( dv.annotationType ()
.getSimpleName () + ":" + dv.value () );
}
}
}
}
}
//输出结果
annotation for parameter1
QueryParam:action
annotation for parameter2
QueryParam:sort
DefaultValue:asc
https://blog.csdn.net/javazejian/article/details/71860633
三、 类加载
3.1 定义
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过类的加载,类的连接,类的初始化这三个步骤对类进行初始化,如果不出现意外,JVM将会连续完成这三个步骤。
类的加载
就是指将class文件读入内存,并为之创建一个java.lang.Class对象
任何类被使用时,系统都会为之建立一个java.lang.Class对象
3.2 类加载器
作用
负责将.class文件加载到内存中,并为之生成对应的java.lang.Class对象
ClassLoader是负责加载类的对象
demo:
public class ClassLoaderDemo {
public static void main(String[] args) {
// static ClassLoader getSystemClassLoader();返回用于委派的类型类加载器
ClassLoader c = ClassLoader.getSystemClassLoader ();
System.out.println (c);
// ClassLoader getParent ();返回父类加载器进行委派
ClassLoader c1 = c.getParent ();
System.out.println (c1);
ClassLoader c2 = c1.getParent ();
System.out.println (c2);//null
}
}