Java学习记录 反射

反射

Java反射机制,可以在程序中访问 已经写好类和方法 的Java对象的描述,实现访问、检测、修改Java本身的信息 等功能

类加载器

Java类加载器是根据类的全名来读取类的二进制字节流到 JVM 中,然后转换目标对应的java.lang.Class对象实例, JVM中默认有三种类加载器 BootstrapClassLoaderExtensionClassLoaderApp ClassLoader

引导启动类加载器

BootstrapClassLoader 主要加载的是JVM自身需要的类,类加载使用 C++语言 实现,是虚拟机的一部分,主要将 JAVA_HOME/lib 下的类库 加载到内存!无法直接应用jar包

扩展类加载器

ExtensionClassLoader 是Java编写,且它的父类加载器是BootstrapClassLoader
sun.misc.Launcher$ExtClassLoader类 实现,主要加载 JAVA_HOME/lib/ext 目录中的类库(也可以更改系统里的环境变量,指定路径目录)

应用类加载器

App ClassLoader 且它的父类加载器是ExtensionClassLoader
sun.misc.Launcher$AppClassLoader类 实现,主要加载应用程序 java -classpath 目录下所有 jar和class文件

类加载器间的关系

  • 启动类加载器,由C++实现,没有父类。
  • 拓展类加载器,由Java实现,父类加载器为null
  • 应用类加载器,由Java实现,父类加载器为ExtClassLoader

双亲委派

它们并非是通常的类继承关系,而是采用组合关系来复用父类加载器的方式加载!

工作原理

类加载器收到类加载请求,它并不会自己去加载,而是把请求委托给父类的加载器去执行加载,如果父类加载器还存在有父类加载器,则进一步向上委托,以此传递请求委托,直至 顶层的启动类加载器。如果顶层加载器加载失败,则将请求返回给 子加载器 尝试自己去加载,依旧向下传递委托。如果加载器完成类加载,则直接成功返回,无需传递请求!委派的好处就是避免有些类被重复加载

故事描述: (坑爹)

他爸生有两个儿子,儿子特别懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子只好自己想办法去完成。。。

顶层类加载器是ClassLoader类 ,是一个抽象类,loadClass()方法是ClassLoader类自己实现的,该方法中的逻辑就是双亲委派模式的实现,代码示例

protected synchronized Class<?> loadClass(String name , boolean resolve) throws ClassNotFoundException{
    //检查是否被加载
    Class c = findLoadedClass(name);
    //如果没加载,则调用父类加载器
    if(c == null){
        try{
            //父类加载器不为空
            if(this.parent != null){
                c = this.parent.c(name , false);
            }else{
                //父类加载器为空,则使用启动类加载器
                c = findBootstrapClassOrNull(name);
            }
        }catch(ClassNotFoundException e){
            //如果父类加载器加载失败,则使用自己的findClass方法进行加载
            c = findClass(name);
        }
    }
    if(resolve){
        resolveClass(c);
    }
    return c;
}

加载配置文件

给项目添加根路径:
项目右键 -> 新建文件夹 -> 设置名 source -> 右键创建的文件夹 -> 标记项目为 -> 资源 根 即可

一般类加载器 加载资源文件默认是src路径下的文件,但是当项目存在 资源根 加载文件这就是该文件夹设置的根!

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;

/**
 * @Author: 柏竹
 * @Description: 一个简洁主义...
 * @Date_Created_in: 2021-03-05 13:41
 * @Modified_By:
 * @Project: 根路径测试
 */
public class Demo {
    public static void main(String[] args) throws IOException {
        InputStream is = Demo.class.getClassLoader().getResourceAsStream("test.txt");
        BufferedReader br = null;
        if (is != null) {
            br = new BufferedReader(new InputStreamReader(is));
        }
        if (br != null){
            System.out.println(br.readLine());
            br.close();
        }
    }
}

类对象

要想了解一个类 , 必须先要获取到该类的字节码文件对象
在Java中,每一个字节码文件,被夹在到内存后,都存在一个对应的Class类型的对象

获取方式

  1. 指定类名是已存在的。 获取 类对象
    包名.类名.class 获取 类对象
  2. 指定类对象 获取 类对象
    Class 对象.getClass()
  3. 知道类名称 获取 类对象
    Class.forName(包名+类名)

点击代码示例* (类对象获取)

构造方法

Class Constructor<T>
java.lang.Object
java.lang.reflect.AccessibleObject
java.lang.reflect.Executable
java.lang.reflect.Constructor<T>

获取构造方法 的前提 需要获取指定类的对象。通过类对象的方法获取构造方法,将返回Constructor类型对象,每个Constructor对象代表一个构造方法

获取构造方法:

返回方法说明
ConstructorClass.getConstructor(Class<?>···parameterTypes)获取 权限为public的指定构造方法
Constructor[]Class.getConstructors() 获取 所有权限为public(公开)的构造方法
ConstructorClass.getDeclaredConstructor(Class<?>···parameterTypes)获取 所有权限的单个构造方法
Constructor[]Class.getDeclaredConstructors() 获取 所有权限的全部构造方法,按声明顺序排列(所有权限)

Constructor类 常用方法: (获取更多方法自行API)

返回方法说明
StringgetName()获取 构造方法的名字
Class[]getParameterTypes()获取 构造方法参数类型的数组
booleanisVarArgs()是否带有可变数量的参数
Class[]getExceptionTypes()获取 构造方法可能抛出的异常类型
Object TnewInstance(Object··· initargs)指定参数创建 该类对象的构造方法。如方法无参,则创建无参的构造方法
voidsetAccessible(boolean bool)是否无视访问权限检查

通过 java.lang.reflect.Modifier类 来解析部分无法识别的信息,比如getModifiers() 返回的值是需要解析的

点击代码示例* (构造方法获取)

方法

Class Method

java.lang.Object
java.lang.reflect.AccessibleObject
java.lang.reflect.Executable
java.lang.reflect.Method

通过类的方法访问方法,将返回Method类型对象,每个Method对象代表一个方法

获取类的方法

返回方法说明
MethodClass.getMethod(String name , Class<?>····parameterTypes)获取指定方法
MethodClass.getDeclaredMethod(String name , Class<?>····parameterTypes) 获取所有权限的 指定方法
Method[]Class.ethods() 获取所有权限的指定方法
Method[]Class.getDeclaredMethods() 获取 所有权限的全部方法,按声明顺序排列

Method类 常用方法 (获取更多方法自行API)

返回方法说明
StringgetName() 获取方法名称
Class[]getParameterTypes()获取参数的类型
ClassgetReturnType()获取方法返回的类型
Class[]getExceptionTypes()返回方法抛出的异常类型
Objectinvoke(Object obj , Object … args)指定参数args指定obj方法
BooleanisVarArgs()带有可变数量的参数,则true
intgetModifiers()获取方法的修饰符(呈现形式整数)
voidsetAccessible(boolean bool)是否无视访问权限检查

点击代码示例* (方法获取及方法使用)

属性

Class Field

java.lang.Object
java.lang.reflect.AccessibleObject
java.lang.reflect.Field

通过方法访问成员变量,将返回Field类型对象,每个Field对象代表一个成员变量
**注意: ** 属性必须要有修饰符修饰才可以获取类属性

获取属性

返回方法说明
FieldClass.getField(String name) 获取 指定属性
FieldClass.getDeclaredField(String name) 获取 所有权限的 指定属性
Field[]Class.getFields() 获取 所有属性
Field[]Class.getDeclaredFields() 获取 所有权限的全部属性,按声明顺序排列

Field类 常用方法 (获取更多方法自行API)

返回方法说明
StringgetName() 获取 属性名
classgetType() 获取 该是属性类型的class对象
Objectget(Object obj) 指定对象obj中成员变量的值进行返回
voidset(Object obj , Object value) 指定对象obj中成员变量的值置为value
voidsetAccessible(boolean flag) 设置是否忽略权限限制直接访问私有成员
intgetModifiers() 获取该成员变量修饰符的整型

点击代码示例* (类属性获取)

注解

Class Annotation

java.lang.Object
java.text.Annotation

对Annotation类型未了解,可前去网址了解:点击了解

访问的前提注解要有该注解@Retention(RetentionPolicy.RUNTIME)

获取注解

返回方法说明
AnnotationgetAnnotation(Class annotationClass) 获取指定的Annotation,不存在则返回null
Annotation[]getAnnotations() 获取所有的Annotation

点击代码示例* (注解获取及使用)

代码索引

类对象

返回*

package sanscan;
/**
 * @Author: 柏竹
 * @Description: 一个简洁主义...
 * @Date_Created_in: 2021-03-05 19:05
 * @Modified_By:
 * @Project: 获取类
 */
public class Demo {
    
    public static void main(String[] args) throws ClassNotFoundException {
        //No.1 , 指定 包名.类名.class 加载类
        Class<Book> c1 = sanscan.Book.class;
        System.out.println(c1);
        
        //No.2 , 指定对象获取类对象
        Book b = new Book();
        Class<Book> c2 = (Class<Book>) b.getClass();
        System.out.println(c1 == c2);
        
        //No.3 , 通过类名获取
        Class<Book> c3 = (Class<Book>) Class.forName("sanscan.Book");
        System.out.println(c3);
        System.out.println(c1 == c2 && c1 == c3);
    }
}
class Book{}

/*
在调用时, 如果类在内存中不存在, 则会加载到内存 ! 如果类已经在内存中存在, 不
会重复加载, 而是重复利用 !
*/

构造方法

返回*

package kkb;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @Author: 柏竹
 * @Description: 一个简洁主义...
 * @Date_Created_in: 2021-03-05 21:08
 * @Modified_By:
 * @Project: 获取构造方法
 */
public class Demo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //(注意:我创建了kkb包)
        Class<Student> sClass = (Class<Student>) Class.forName("kkb.Student");
        
        //No.1 获取无参
        Constructor<Student> c1 = sClass.getConstructor();
        Student s = c1.newInstance();
        System.out.println(s);
    
        System.out.println("==============");
        
        //No.2 获取指定参数类型的
        Constructor<Student> c2 = sClass.getConstructor(String.class , int.class);
        Student s2 = c2.newInstance("张三" , 22);
        System.out.println(s2);
    
        System.out.println("==============");
    
        //No.3 获取所有权限及构造方法
        Constructor<Student>[] c3 = (Constructor<Student>[]) sClass.getDeclaredConstructors();
        Student s3;
        for (Constructor<Student> container : c3) {
            System.out.println(container);
        }
    
    }
}

class Student{
    String name;
    int age;
    
    public Student(){}
    
    private Student(String...strs){
        for (String s : strs) {
            System.out.println(s);
        }
    }
    
    public Student(String name , int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

/*	方法可自行测试

Student{name='null', age=0}
==============
Student{name='张三', age=22}
==============
public kkb.Student(java.lang.String,int)
private kkb.Student(java.lang.String[])
public kkb.Student()

*/

方法

返回*

package kkb;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @Author: 柏竹
 * @Description: 一个简洁主义...
 * @Date_Created_in: 2021-03-06 9:39
 * @Modified_By:
 * @Project: 获取方法
 */
public class Demo {
    public static void main(String[] args) throws Exception {
        //获取 类对象 (注意:我创建了kkb包)
        Class<Person> aClass = (Class<Person>) Class.forName("kkb.Person");
        //获取 类构造方法
        Constructor<Person> constructor = aClass.getConstructor(String.class , int.class);
        //获取 类实例的对象
        Object o = constructor.newInstance("柏竹" , 20);
    
        /*No.1
        * 直接获取
        * */
        Method setName = aClass.getMethod("setName" , String.class);
        Method getName = aClass.getMethod("getName");
        System.out.println(setName);
        System.out.println(getName);
    
        System.out.println("===================");
        
        /*No.2
        *   获取所有权限 获取setAge()方法
        * */
        Method setAge = aClass.getDeclaredMethod("setAge", int.class);
        System.out.println(setAge);
    
        System.out.println("===================");
        
        /*No.3
        *   获取所有方法
        * */
        Method[] methods = aClass.getMethods();
        //无视权限进行测试使用
        for (Method tmp : methods) {
            System.out.println(tmp);
        }
    
        System.out.println("===================");
        
        /*
        * 方法使用
        * */
        System.out.println("\n-----模拟使用方法");
        //获取 该方法所有权限
        setAge.setAccessible(true);
        System.out.println("使用前 : "+o);
        setAge.invoke(o , 24);
        System.out.println("使用后 : "+o);
        
        System.out.println("\n-----获取方法名");
        System.out.println(" ["+setAge.getName()+"] ");
        
        System.out.println("\n-----获取方法参数类型");
        Method test = aClass.getMethod("test", String.class, int[].class);
        for (Class tmp : test.getParameterTypes()) {
            System.out.println(" ["+tmp+"] ");
        }
        
        System.out.println("\n-----获取方法返回类型");
        System.out.println(" ["+getName.getReturnType()+"] ");
        
    }
}

class Person{
    String name;
    int age;
    
    public Person() {
    }
    
    public Person(String name , int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    /**
     * 私有修饰
     * @param age
     */
    private void setAge(int age) {
        this.age = age;
    }
    
    public void test(String str , int...numAll){
        System.out.println("参数方法测试");
    }
    
    @Override
    public String toString() {
        return "person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

/*

public void kkb.Person.setName(java.lang.String)
public java.lang.String kkb.Person.getName()
===================
private void kkb.Person.setAge(int)
===================
public java.lang.String kkb.Person.getName()
public java.lang.String kkb.Person.toString()
public void kkb.Person.test(java.lang.String,int[])
public void kkb.Person.setName(java.lang.String)
public int kkb.Person.getAge()
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
===================

-----模拟使用方法
使用前 : person{name='柏竹', age=20}
使用后 : person{name='柏竹', age=24}

-----获取方法名
 [setAge] 

-----获取方法参数类型
 [class java.lang.String] 
 [class [I] 

-----获取方法返回类型
 [class java.lang.String] 

*/

属性

返回*

package kkb;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

/**
 * @Author: 柏竹
 * @Description: 一个简洁主义...
 * @Date_Created_in: 2021-03-06 11:13
 * @Modified_By:
 * @Project: 属性获取及使用
 */
public class Demo {
    public static void main(String[] args) throws Exception {
        Class<Person> aClass = (Class<Person>) Class.forName("kkb.Person");
        Constructor<Person> ct = aClass.getConstructor(String.class, int.class, String.class);
        Object o = ct.newInstance("柏竹" , 20 , "18122335634");
        
        //No.1 直接获取
        Field name = aClass.getField("name");
        System.out.println(name);
    
        System.out.println("=============");
        
        //No.2 获取所有权限 获取手机号码
        Field phoneNumber = aClass.getDeclaredField("phoneNumber");
        phoneNumber.setAccessible(true);
        System.out.println(phoneNumber);
    
        System.out.println("=============");
        
        //No.3 获取 所有属性
        //无法访问私有属性
        for (Field tmp : aClass.getFields()) {
            System.out.println(tmp);
        }
        
        System.out.println("=============");
        
        /*
        * 方法使用
        * */
        System.out.println("------获取属性名");
        System.out.println(" ["+phoneNumber.getName()+"] ");
    
        System.out.println("------获取属性类型");
        System.out.println(" ["+phoneNumber.getType()+"] ");
    
        System.out.println("------获取属性值");
        System.out.println(" ["+phoneNumber.get(o)+"] ");
    
        System.out.println("------设置属性值");
        phoneNumber.set(o , "18122334455");
        System.out.println(" ["+o+"] ");
    }
}

class Person{
    public String name;
    public int age;
    private String phoneNumber;
    
    public Person() {
    }
    
    public Person(String name , int age , String phoneNumber) {
        this.name = name;
        this.age = age;
        this.phoneNumber = phoneNumber;
    }
    
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", phoneNumber=" + phoneNumber +
                '}';
    }
}

/*

public java.lang.String kkb.Person.name
=============
private java.lang.String kkb.Person.phoneNumber
=============
public java.lang.String kkb.Person.name
public int kkb.Person.age
=============
------获取属性名
 [phoneNumber] 
------获取属性类型
 [class java.lang.String] 
------获取属性值
 [18122335634] 
------设置属性值
 [Person{name='柏竹', age=20, phoneNumber=18122334455}] 


*/

注解

返回*

执行测试类

package kkb;

import java.lang.reflect.Field;

/**
 * @Author: 柏竹
 * @Description: 一个简洁主义...
 * @Date_Created_in: 2021-03-06 16:32
 * @Modified_By:
 * @Project: 反射获取注解
 */
public class Demo {
    public static void main(String[] args) throws Exception {
        Class<Book> aClass = (Class<Book>) Class.forName("kkb.Book");
        
        //通过反射 表详细
        MyAnnotationTable at = aClass.getAnnotation(MyAnnotationTable.class);
        String value = at.tableName();
        System.out.println("表名 : " + value);
        
        //属性
        for (Field tmp : aClass.getDeclaredFields()) {
            MyAnnotationField af = tmp.getAnnotation(MyAnnotationField.class);
            System.out.println(tmp.getName() +
                    "属性 , 对应数据库中的字段为 : "+ af.name()+
                    " , 数据类型 : "+af.type()+
                    " , 数据长度 : "+af.length()
            );
        }
    }
}
/*

表名 : test_Book
id属性 , 对应数据库中的字段为 : id , 数据类型 : int , 数据长度 : 20
name属性 , 对应数据库中的字段为 : name , 数据类型 : varchar , 数据长度 : 50
info属性 , 对应数据库中的字段为 : info , 数据类型 : varchar , 数据长度 : 200

*/

Book类

package kkb;

import java.util.Objects;

/**
 * @Author: 柏竹
 * @Description: 一个简洁主义...
 * @Date_Created_in: 2021-03-06 16:44
 * @Modified_By:
 * @Project: 数据
 */
@MyAnnotationTable(tableName = "test_Book")
public class Book {
    @MyAnnotationField(name = "id" , type = "int" , length = 20)
    private int id;
    @MyAnnotationField(name = "name" , type = "varchar" , length = 50)
    private String name;
    @MyAnnotationField(name = "info" , type = "varchar" , length = 200)
    private String info;
    
    public Book() {
    }
    
    public Book(int id , String name , String info) {
        this.id = id;
        this.name = name;
        this.info = info;
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Book book = (Book) o;
        return id == book.id &&
                Objects.equals(name , book.name) &&
                Objects.equals(info , book.info);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(id , name , info);
    }
    
    public int getId() {
        return id;
    }
    
    public void setId(int id) {
        this.id = id;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public String getInfo() {
        return info;
    }
    
    public void setInfo(String info) {
        this.info = info;
    }
    
    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", info='" + info + '\'' +
                '}';
    }
}

注解MyAnnotationField

package kkb;

import java.lang.annotation.*;

/**
 * @Author: 柏竹
 * @Description: 一个简洁主义...
 * @Date_Created_in: 2021-03-06 16:34
 * @Modified_By:
 * @Project: 字段
 */
@Inherited
@Documented
@Target (ElementType.FIELD)
@Retention (RetentionPolicy.RUNTIME)
public @interface MyAnnotationField {
    /**
     * 列名
     * @return
     */
    String name();
    /**
     * 类型
     * @return
     */
    String type();
    /**
     * 数据长度
     * @return
     */
    int length();
}

注解MyAnnotationTable

package kkb;

import java.lang.annotation.*;

/**
 * @Author: 柏竹
 * @Description: 一个简洁主义...
 * @Date_Created_in: 2021-03-06 16:32
 * @Modified_By:
 * @Project: 表名
 */
@Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotationTable {
    /**
     * 表名称
     * @return
     */
    String tableName();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值