Java学习之:反射-Class类

1.认识反射

反射:对象的反向处理。根据对象倒推类的组成。
正向处理:先有类,然后产生对象

反射核心类Class类(专门描述其他类的组成)
Object类中取得对象的Class对象

public final native Class<?> getClass();

Class类作用:描述接口与类的组成
Class对象由JVM在第一次加载类时产生,并且全局唯一。

1.1取得任意类Class对象的方式

(1)对象.getClass() Object类提供

(2)类名称.class

(3)Class.forName(类全名称)

Date date = new Date();
System.out.println(date.getClass());

System.out.println(Date.class);

System.out.println(Class.forName("java.util.Date"));

1.2 类的实例化对象方式

第一种:通过类的构造方法实例化对象

第二种:
(1)Class类的newInstance()方法实例化对象
实际调用的是类中的无参构造,如果类中没有无参构造或者无参构造的权限不是public此方法无法使用。(例如Integer类就没有无参构造)

(2)Constructer类的如下方法:
public T newInstance(Object ... initargs)
若类中没有无参构造,则只能调用Contructer类提供的newInstance()方法使用有参构造来实例化对象

第三种:序列化和反序列化

1.3反射与工厂设计模式

具体实现请看以下链接 https://blog.csdn.net/qq_43777322/article/details/90112629

2.反射和类操作

2.1取得父类&父接口信息

取得包信息 - Package(描述包信息的类)
public Package getPackage();

取得类名:
(1)类的全限定名:包名+ 类名
classz.getName()
(2)类名
getSimpleName()
(3)取得父类的Class对象:
getSuperClass() : Class<? super T>

(4)取得实现的父接口Class对象
getInterfaces() : Class<?>[]

2.2 反射与构造方法 - Constructor(描述类构造方法信息)

(1)取得类中指定参数类型的构造方法
public Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException

(2)取得类中所有构造方法

public Constructor<?>[] getConstructors() throws SecurityException
取得类中所有权限为public的构造方法

public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
取得类中所有权限的构造方法

class Person{
    private String name;
    private  int age;

    private Person() {
    }

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

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

public class TestReflect {
    public static void main(String[] args) throws Exception {
        //通过类名取得Class类的对象
        Class classz = Person.class;
        //取得有参构造
        Constructor constructor =classz.getConstructor(String.class,int.class);
        //实例化对象
        //相当于调用Person person = new Person("张三",18);
        Person person = (Person) constructor.newInstance("张三",18);
        System.out.println(person);
    }
}

2.3 反射与普通方法 - Method

2.3.1 取得类中指定名称与参数的普通方法

String name:方法名称
Class<?>… parameterTypes: 方法的参数类型

public Method getMethod(String name, Class<?>... parameterTypes)(Class类的方法)

public Method getDeclaredMethod(String name, Class<?>... parameterTypes)

2.3.2 取得类中所有普通方法

public Method[] getMethods() throws SecurityException
取得本类以及父类中所有权限为public的普通方法(包含静态方法)

public Method[] getDeclaredMethods() throws SecurityException
只能取得本类中所有方法(包含private方法)

2.3.3 调用普通方法

obj:类的实例化对象
args:普通方法参数

public Object invoke(Object obj, Object... args)

class Person{
    private String name;

    public String getName() {
        return name;
    }

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

public class TestReflect {

    public static void main(String[] args) throws Exception {
/*        Person person =new Person();
        person.setName("张三");
        System.out.println(person.getName());*/
        //1.取得Class对象
        Class<Person>  cls = Person.class;
        //2.组装方法名称
        String setMethodName = "set" + initCap("a");
        String getMethodName = "get" + args[0];
        //3.取得Method对象
        Method setMethod = cls.getMethod(setMethodName,String.class);
        Method getMethod = cls.getMethod(getMethodName);
        //4.取得Person类的实例化对象,然后调用方法
        Person person = cls.newInstance();
        setMethod.invoke(person,"张三");
        System.out.println(getMethod.invoke(person));

    }
    private static String initCap(String str) {
        return str.substring(0,1).toUpperCase() + str.substring(1) ;
    }
}

2.4 反射与普通属性

2.4.1 取得类中指定名称属性

public Field getField(String name)
public Field getDeclaredField(String name)

2.4.2 取得类中所有属性

public Field[] getFields() throws SecurityException
取得本类以及父类中所有权限为public的属性(包含静态属性)

public Field[] getDeclaredFields() throws SecurityException
只能取得本类中所有方法(包含private方法)

class Person{
    public static String test;
    private String name;
    public int age;
}

class Student extends Person {
    private String school;
    public String className;
}

public class TestReflect {

    public static void main(String[] args) throws Exception {
        Class<Student> cls = Student.class;
        {
            Field[] fields = cls.getFields();
            for (Field field: fields) {
                System.out.println(field);
            }
        }
        System.out.println("-----------");
        {
            Field[] fields = cls.getDeclaredFields();
            for (Field field: fields) {
                System.out.println(field);
            }
        }
    }

}

2.4.3( Field类提供)设置与取得值

1.设置:
obj:类的实例化对象
value:要设置的值
public void set(Object obj, Object value)

2.取得:
obj:类的实例化对象
public Object get(Object obj)

3.取得属性类型
public Class<?> getType()

class Person{
    public int age;
}

public class TestReflect {
    public static void main(String[] args) throws Exception {
        Class<Person> cls = Person.class;
        //取得Field对象
        Field field = cls.getField("age");
        //产生Person实例化对象
        Person person = cls.newInstance();
        //set&get
        field.set(person,20);
        System.out.println(field.get(person));
        System.out.println(field.getType());
    }
}

2.5 动态破坏封装(反射特性)

在一次JVM进程中,下次想要破坏,还要再次设置 且只能通过反射调用
Constuctor,Method,Field类都继承AccessibleObject类,此类中有一个破坏封装的方法

//如果flag设置为true,就可以访问到被封装的
public void setAccessible(boolean flag) throws SecurityException

class Person{
    private int age;
}

public class TestReflect {
    public static void main(String[] args) throws Exception {
        //取得类对象
        Class<Person> cls = Person.class;
        //取得属性对象,因为age是私有的,所以getField()获取不到
        Field field = cls.getDeclaredField("age");
        //取得实例化对象
        Person person = cls.newInstance();
        //动态破坏封装
        field.setAccessible(true);
        field.set(person,20);
        System.out.println(field.get(person));
    }
}

只能通过反射调用:如果直接正向调用,person.age = 20;编译都无法通过

3. ClassLoader类加载器

3.1 定义

类加载:通过一个类的全名称来获取此类的二进制字节流

类加载器:实现类加载的功能模块

3.2 JDK内置三大加载器

3.2.1 BootStrap(启动类加载器)

(1)使用C++实现,是JVM自身的一部分,独立于JVM外部,并且无法被Java程序直接引用

(2)负责将存放于于Java_HOME\lib目录下的能被JVM识别的所有类库(例如rt.jar - java基础类库)加载到JVM中。

3.2.2 ExtClassLoader扩展类加载器

(1)使用Java语言实现,可以被Java程序直接引用

(2)负责将Java_HOME\lib\ext (xml文件解析类,界面框架类)目录下的所有能被JVM识别的类库。

3.2.3 AppClassLoader(应用程序类加载器)

(1)使用Java程序实现,如果没有用户自定义类加载器,则AppClassLoader就是程序中默认的类加载器

(2)负责加载用户classPath指定的类库

3.2.4 三大加载器关系

除了BootStrap没有父加载器,其它类加载器
都有父加载器

3.3 类加载器的双亲委派模型(定义,工作流程,存在意义)

定义:
四个类加载器的层次关系
在这里插入图片描述
工作流程:
加载一个类都要经过顶层加载器,如果顶层加载器在它所加载的范围内
找不到该类,就会返回给子类加载器去加载。

意义:
双亲委派模型对于保证Java程序的稳定运行十分重要
例如java.lang.Object,它存放在rt.jar中,由于双亲委派模型的存在,无论哪一类类加载器要加载此类,都会委派给BootStrap去进行加载,因此,Object类在程序的各种类加载器环境中都是同一个类。

比较两个类是否相等的前提条件:这两个类是由一个类加载器加载的
否则即使两个类来自同一个Class文件,被同一个JVM加载,这两个类也不相等

4.动态代理

代理类不在实现某一个接口,而是实现InvocationHandler接口。
只有实现了InvocationHandler接口的类才具备动态代理的功能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值