java——反射

一、反射概述

 

 

二、理解Class类

1.类加载的过程

  • 首先程序通过javac命令,编译成字节码文件.class
  • 然后使用java命令运行.class文件,相当于把字节码文件加载进内存。这个过程就是类加载的过程。
  • 加载到内存中的类,我们叫做运行时类,运行时类是Class类的对象。(体现了万物皆对象,类也是对象)
  • 换句话说,Class类的对象就是运行时类

 

三、获取Class类的实例的四种方式

——Class类的实例其实就是运行时类


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

        //方式一:通过运行时类的属性.class
        Class clazz1 = persons.class;
        System.out.println(clazz1); // class persons

        //方式二:通过运行时类的对象的getClass()方法
        persons p = new persons();
        Class clazz2 = p.getClass();
        System.out.println(clazz2); // class persons

        //方式三:通过Class的静态方法——forName(String className)
        Class clazz3 = Class.forName("persons");
        System.out.println(clazz3); //class persons

        Class clazz4 = Class.forName("java.lang.String");//这里如果写"String"就会报错,要写全
        System.out.println(clazz4); // class java.lang.String

        //方式四:使用类加载器ClassLoader()
        ClassLoader classLoader = persons.class.getClassLoader();
        Class clazz5 = classLoader.loadClass("persons");
        System.out.println(clazz5);

        //说明person类加载进内存的时候只会加载一个(加载多了也没必要)。因此上面四种方式叫如何获取Class类的实例,而不是如何创建Class类的实例
        System.out.println(clazz1==clazz2);//true
        System.out.println(clazz1==clazz3);//true
        System.out.println(clazz1==clazz5);//true
    }
}

class persons{
    private String name;
    public int age;

    @Override
    public String toString() {
        return "name:"+name+"_age:"+age;
    }

    public persons(){}

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

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

    private void show(){
        System.out.println("我要进大厂!");
    }

    public String getName(){
        return this.name;
    }
}

 

四、类的加载与ClassLoader的理解

  • 每个类或者接口等在编译后都会有一个.class字节码文件
  • 类加载器会把.class文件加载进内存,并将这些静态数据转换成方法区的运行时数据结构。
  • 然后在中会生成一个个Class类的对象(Class类的对象也就是一个一个的类和接口等,而且每个类只会加载一个),作为方法区中类数据的访问入口

  • 类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象。
 

五、通过反射的方式创建运行时类的对象

——以前我们创建类的对象都是通过new的方式,这里用反射的方式

——运行时类也就是之前我所说的类的概念,只不过被加载进内存后,就变成了运行时类,也是Class类的对象

 

六、newInstance()方法


public class HTreflection {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException {

//        //如果不适用泛型,clazz.newInstance()返回的是一个Object类型,后面还需要强转
//        Class clazz = persons.class;
//        Object obj = clazz.newInstance();
//        persons p = (persons)obj;

        Class<persons> clazz = persons.class;//反射都要从Class开始

        /*
        Class的对象.newInstance():返回对应的运行时类的对象,其实内部调用了空参构造器persons(){}来创建对象
        因此要想使用Class的对象.newInstance(),必须满足以下条件:
            1.此persons类要有空参构造器,否则InstantiationException
            2.此persons类的空参构造器的的权限要够用(通常设置public),否则非法访问异常IllegalAccessException
        在javabean中要求提供一个public的空参构造器,原因:
            1.便于通过反射,创建运行时类的对象
            2.便于子类继承此运行时类,默认用用super()时,保证父类有此构造器
         */
        persons p = clazz.newInstance();

        System.out.println(p);
        
    }
}

class persons{
    private String name;
    public int age;

    @Override
    public String toString() {
        return "name:"+name+"   age:"+age;
    }

    public persons(){}

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

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

    private void show(){
        System.out.println("我要进大厂!");
    }

    public String getName(){
        return this.name;
    }
}

七、通过举例体会反射的动态性

    //体会反射的动态性
    @Test
    public void test2(){

        for(int i = 0;i < 100;i++){
            int num = new Random().nextInt(3);//产生一个随机数:0,1,2
            String classPath = "";
            switch(num){
                case 0:
                    classPath = "java.util.Date";
                    break;
                case 1:
                    classPath = "java.lang.Object";
                    break;
                case 2:
                    classPath = "com.atguigu.java.Person";
                    break;
            }

            try {
                Object obj = getInstance(classPath);
                System.out.println(obj);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }



    }

    /*
    创建一个指定类的对象。
    classPath:指定类的全类名
     */
    public Object getInstance(String classPath) throws Exception {
       Class clazz =  Class.forName(classPath);
       return clazz.newInstance();
    }
  • 怎么从上面代码来理解通过反射可以让java语言具有动态性?
  • 上面的程序通过随机数来决定造哪个对象,在程序运行前我们不知道程序会造哪个对象,在这里体现了动态性。
  • 到哪还会有人说,这个动态性难道不是因为随机数才让java具有动态性吗?如果用new的方式造对象,也通过随机数和switch-case来决定到底造哪个对象,也可以体现动态性啊?
  •  

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值