Java高级开发之反射

一、认识反射

1.定义

反射指的是对象的反向处理,根据对象倒推类的组成。
核心类为Class类(专门描述其他类的组成)
Class类描述接口与类的组成,class对象在JVM第一次加载类时产生,并且全局唯一。

2.class对象的三种实例化模式

1.调用对象.getClass()取得其class对象;
2.类名称.class取得class对象;
3.Class.forName(类全名称);

通过反射实例化对象:public T newInstance(){}
实际上调用类中的无参构造,若类中没有无参构造或者权限不是public,此方法无法使用。

Class <Date> cls = Date.class;
Date date = cls.newInstance();

3.反射与工厂设计模式

interface IFruit{
    void eat();
}
class Apple implements IFruit{
    @Override
    public void eat() {
        System.out.println("eat an apple");
    }
}
class Orange implements IFruit{
    @Override
    public void eat() {
        System.out.println("eat an orange");
    }
}
class Factory{
    public static IFruit getInstanceof(String fruitName)throws Exception{
        IFruit fruit = null;
        Class<?> cls = Class.forName(fruitName);
        fruit = (IFruit) cls.newInstance();
        return fruit;
    }
}

public class Test {
    public static void main(String[] args) throws Exception {
        IFruit fruit = Factory.getInstanceof("com.test.Reflect.Orange");
        fruit.eat();
    }
}

引入反射后,每当新增接口子类,无需去修改工厂类代码就可以很方便的进行接口子类扩容。以上这种工厂类代码我们称之为简单工厂模式。

二、反射与类操作

1.取得父类&父接口信息

取得包信息

public Package getPackage(){} //Package类用来描述包信息

取得父类的Class对象

public native Class<? super T> getSuperclass(){}

取得父接口的Class对象

public Class<?>[] getInterfaces() {}


interface IFruit1{}
interface IMess{}
class clson{}
class Cls extends clson implements IFruit1,IMess{}

public class test8_2 {
    public static void main(String[] args) {
        Class <?> cls = Cls.class;//取得Class类对象
        System.out.println(cls.getPackage().getName());//取得包名称
        System.out.println(cls.getSuperclass().getName());//父类的class类对象
        Class<?> [] arr = cls.getInterfaces();
        for (Class<?> a:arr) {
            System.out.println(a.getName());//取得父接口的Class类对象
        }
    }
}

2.反射调用构造

取得类中指定参数类型的构造方法

public Constructor<T> getConstructor(Class<?> ...parameterTypes){}

public Constructor<T> getDeclaredConstructor(Class<?> ...parameterTypes){}

取得类中所有构造方法

public Constructor<?>[] getConstructors() throws SecurityException{ } //public权限

public Constructor<?>[] getDeclaredConstructors() throws SecurityException{} //所有权限

Constructor中实例化对象方法:

public T newInstance(Object ... initargs) throws 
InstantiationException, IllegalAccessException,               
IllegalArgumentException, InvocationTargetException{}
//若类中没有无参构造,只能调用Constructor类
//提供的newInstance方法使用有参构造实例化对象。

3.反射调用普通方法

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

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

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

取得全部普通方法

public Method[] getMethods() throws SecurityException
//取得本类以及父类所有public方法(包括静态方法)
public Method[] getDeclaredMethods() throws SecurityException
//取得本类中任意权限的所有方法

调用普通方法

public Object invoke(Object obj, Object... args)throws IllegalAccessException, IllegalArgumentException,InvocationTargetException

class Person1{
    private String name;

    public String getName() {
        return name;
    }

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

public class test8_1 {
    public static void main(String[] args) throws Exception {
        //取得class对象
        Class<Person> cls = Person.class;
        //取得Method对象
        String setMethodName = "setName";
        String getMethodName = "getName";
        Method setMethod = cls.getMethod(setMethodName,String.class);
        Method getMethod = cls.getMethod(getMethodName);
        //取得实例化对象
        Person per = cls.newInstance();
        setMethod.invoke(per,"张三");
        System.out.println(getMethod.invoke(per));
    }

4.反射调用类中属性

取得类中指定名称属性

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

取得类中所有属性

public Field[] getField()//本类及父类publlic权限的所有属性
public Field[] getDeclaredField()//本类所有属性

设置与取得值

public void set(Object obj,Object value)
pulic Object get(Object obj)
取得属性类型:public Class<?> getType()

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

Constructor、Method、Field类都继承了AccessibleObject类,此类中有一个破坏封装的方法:
public void setAccessible(boolean flag)throws SecurityException

class test1{
    private int age;
}
public class test8_2 {
    public static void main(String[] args) throws Exception, IllegalAccessException, InstantiationException {
        Class<?> cls = test1.class;
        Object obj = cls.newInstance();
        Field field = cls.getDeclaredField("age");
        field.setAccessible(true);
        field.set(obj,20);
        System.out.println(field.get(obj));
    }
}

三、ClassLoader类加载器

1.定义

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

2.JDK内置的三大类加载器

(1)BootStrap–启动类加载器

使用c++实现,是JVM自身的一部分,独立于JVM外部,并且无法被Java程序直接调用;
负责将存放于JAVA_HOME\lib目录下的能被JVM识别的所有库类加载到JVM中。

(2)ExtClassLoader–扩展类加载器

使用Java语言实现,可以被Java程序直接引用;
负责将存放于JAVA_HOME\lib\ext(xml文件解析类,界面框架类)目录下能被JVM识别的所有类库加载到JVM中。

(3)AppClassLoader–应用程序类加载器

使用Java程序实现,若用户没有自定义类加载器,则它为程序中默认的类加载器;
负责加载用户ClassPath指定的类库。

3.类加载器的双亲委派模型

(1)定义

在这里插入图片描述

四种类加载器的层次关系称为类加载器的双亲委派模型。

(2)工作流程

如果一个类加载器收到了类加载的请求,首先自己不会去尝试加载此类,而是将类加载请求委托给父类加载器完成,每一层的类加载器都是如此。只有当父加载器无法加载此类时,子加载器才会尝试自己去加载。

(3)意义

双亲委派模型对于java程序稳定运行十分重要。例如Java.lang.Object,他存放在rt.jar中,由于双亲委派模型的存在,无论在哪一类类加载器要加载此类,最终都是委派给处于顶端的启动类加载器进行加载,因此,Object类在程序的各种类加载器环境中都是一个类。

比较两个类是否相等的前提条件:这两个类是由同一个类加载器加载的。否则即使两个类来源于同一个class文件,被同一个JVM加载,只要加载这两个类的类加载不同,这两个类注定不相等。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值