Java反射基础_SXL


引言

做个俗人,贪财好色,一身正气。


一、反射基本概念

JAVA反射机制是程序在运行状态中,可以构造任意一个类的对象 , 可以了解任意一个对象所属的类,了解任意一个类的属性和成员方法,以及可以调用它们。这就是反射机制,是动态语言的关键。


二、类加载器

Java类加载器(Java Classloader)是Java运行时环境(Java Runtime Environment)的一部分,负责动态加载Java类到Java虚拟机的内存空间中。

java默认有三种类加载器,BootstrapClassLoader、ExtensionClassLoader、AppClassLoader。

BootstrapClassLoader(引导启动类加载器):嵌在JVM内核中的加载器,该加载器是用C++语言写的,主要负载加载JAVA_HOME/lib下的类库,引导启动类加载器无法被应用程序直接使用。

ExtensionClassLoader(扩展类加载器):ExtensionClassLoader是用JAVA编写,且它的父类加载器是Bootstrap。是由sun.misc.Launcher$ExtClassLoader实现的,主要加载JAVA_HOME/lib/ext目录中的类库。
它的父加载器是BootstrapClassLoader。

App ClassLoader(应用类加载器):
App ClassLoader是应用程序类加载器,负责加载应用程序classpath目录下的所有jar和class文件。它的父加载器为ExtClassLoader类通常是按需加载,即第一次使用该类时才加载。
由于有了类加载器,Java运行时系统不需要知道文件与文件系统。学习类加载器时,掌握Java的委派概念很重要。

双亲委派模型:如果一个类加载器收到了一个类加载请求,它不会自己去尝试加载这个类,而是把这个请求转交给父类加载器去完成。
每一个层次的类加载器都是如此。因此所有的类加载请求都应该传递到最顶层的启动类加载器中,只有到父类加载器反馈自己无法完成这个加载请求(在它的搜索范围没有找到这个类)时,子类加载器才会尝试自己去加载。委派的好处就是避免有些类被重复加载。

默认加载的是src路径下的文件,但是当项目存在resource root目录时,就变为了加载resource root下的文件。

源码:

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

加载resource目录下的资源文件

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

public class Test {

    public static void main(String[] args) throws IOException {
    	// 默认加载的是src路径下的文件,但是当项目存在resource root目录时,就变为了加载resource root下的文件。
        InputStream is = test.class.getClassLoader().getResourceAsStream("config.txt");
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String text = br.readLine();
        System.out.println(text);
        br.close();

    }
}


三、反射获取

3.1 Class对象获取

public class Test {

    public static void main(String[] args) throws ClassNotFoundException {

        // 第一种方式,通过类名.class 加载类
        Class<Test> c1 = Test.class;
        System.out.println(c1);

        // 第二种方式,通过类对象获取类的信息
        Test t = new Test();
        Class<Test> c2 = (Class<Test>) t.getClass();
        System.out.println(c2);

        // 第三种方式 此方法是动态的 合理
        Class c3 = Class.forName("Test");
        System.out.println();
    }
}

3.2 Constructor获取

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

public class Test {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        Class<Person> pClass = (Class<Person>) Class.forName("Person");
        // 找到无参构造方法
        Constructor<Person> c1 = pClass.getConstructor();
        // 使用无参构造方法,创建对象
        Person p1 = c1.newInstance();
        System.out.println(p1);

        // 有参构造
        Constructor<Person> c2 = pClass.getConstructor(String.class, int.class);
        // 使用有参构造方法,创建对象
        Person p2 = c2.newInstance("王五", 12);
        System.out.println(p2);

        // 反射打破封装 外部调用私有 获取所有权限单个构造方法 getDeclaredConstructors 获取数组
        Constructor<Person> c3 = pClass.getDeclaredConstructor(String.class);
        c3.setAccessible(true);
        Person p3 = c3.newInstance("王鲁");
        System.out.println(p3);
    }


}

class Person {

    private String name;

    private int age;

    public Person() {
    }

    private Person(String name) {
        this.name = name;
    }

    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;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

3.3 获取Method

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

public class Test {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        // 加载类
        Class c1 = Class.forName("Person");
        // 获取类的构造方法
        Constructor c = c1.getConstructor();
        Object o = c.newInstance();
        // 获取类方法
        Method setName = c1.getMethod("setName", String.class);
        // getDeclaredMethod可以访问私有的
        Method setAge = c1.getDeclaredMethod("setAge", int.class);
        setAge.setAccessible(true);
        // 参数1:哪个对象执行setName方法
        // 参数2:调用方法时传递的参数 0-n
        setName.invoke(o, "芝麻");
        setAge.invoke(o, 18);
        System.out.println(o);
    }


}

class Person {

    private String name;

    private int age;

    public Person() {
    }

    private Person(String name) {
        this.name = name;
    }

    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;
    }

    private void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

3.4 获取Field

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

public class Test {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {

        // 加载类
        Class c1 = Class.forName("Person");
        // 获取类的构造方法
        Constructor ct = c1.getConstructor();
        Object o = ct.newInstance();

        Field name = c1.getDeclaredField("name");
        name.setAccessible(true);
        name.set(o, "王五");
        System.out.println(o);
    }


}

class Person {

    private String name;

    private int age;

    public Person() {
    }

    private Person(String name) {
        this.name = name;
    }

    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;
    }

    private void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

3.5 获取注解信息

import java.lang.annotation.*;
import java.lang.reflect.Field;

public class Test {

    public static void main(String[] args) throws ClassNotFoundException {
        // 框架大部分内部原理
        Class c = Class.forName("Book");
        /*Annotation[] annotations = c.getAnnotations();
        for (Annotation a : annotations) {
            System.out.println(a);
        }*/

        TableAnnotation ta = (TableAnnotation) c.getAnnotation(TableAnnotation.class);
        String value = ta.value();
        System.out.println(value);

        Field[] fs = c.getDeclaredFields();
        for (Field f : fs) {
            ColumnAnnotation ca = f.getAnnotation(ColumnAnnotation.class);
            System.out.println(f.getName() + "属性对应数据库的字段:" + ca.columnName() + ",数据类型:" + ca.type() + ",数据长度:" + ca.length());
        }

    }

}


@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface TableAnnotation {

    /**
     * 用于标注类对应的表名称
     * @return
     */
    String value();
}

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface ColumnAnnotation {

    /**
     * 描述列名
     * @return
     */
    String columnName();

    /**
     * 描述类型
     * @return
     */
    String type();

    /**
     * 描述长度
     * @return
     */
    String length();
}

@TableAnnotation("Test_Book")
class Book {

    @ColumnAnnotation(columnName = "id", type = "int", length = "11")
    private int id;

    @ColumnAnnotation(columnName = "name", type = "varchar", length = "50")
    private String name;

    @ColumnAnnotation(columnName = "info", type = "varchar", length = "1000")
    private String 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 + '\'' +
                '}';
    }
}

四、内省

基于反射 , java所提供的一套应用到JavaBean的API

一个定义在包中的类 
拥有无参构造器
所有属性私有
所有属性提供get/set方法
实现了序列化接口

这种类, 我们称其为 bean类。
Java提供了一套java.beans包的api , 对于反射的操作, 进行了封装 。

实现对象的get和set方法

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;


public class Test {

    public static void main(String[] args) throws IntrospectionException {
        Class c = Express.class;
        BeanInfo bi = Introspector.getBeanInfo(c);
        PropertyDescriptor[] pds = bi.getPropertyDescriptors();
        for (PropertyDescriptor pd : pds) {
            System.out.println(pd.getReadMethod());
            System.out.println(pd.getWriteMethod());
        }

    }

}


class Express implements Serializable {

    private String number;

    private String name;

    private String phoneNumber;

    private String address;

    private Boolean flag;

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Boolean getFlag() {
        return flag;
    }

    public void setFlag(Boolean flag) {
        this.flag = flag;
    }
}


总结

人生无限,缓缓起航,修正改错,在满足完成任务的条件下,追求完善,全身而退。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值