类的加载到反射reflect

类的加载:

  当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载、连接、初始化这三个步骤来实现对这个类进行初始化。

  加载:

    就是指将class文件加载进入内存,并为之创建一个Class对象

    任何类被使用时,系统都会创建一个Class对象

  连接:

    验证: 是否有正确的内部结构,并且和其他类协调一致

    准备: 负责为类的静态成员分配内存,并设置默认初始化值

    解析: 将类的二进制数据中的符号引用替换为直接引用

  初始化:就是以前我们讲过的初始化步骤

类初始化的时机:

  创建类的实例

  访问类的静态方法或者为类的静态变量赋值

  使用反射机制来强制创建某个类或接口对应的java.lang.Class对象

  初始化某个类的子类

  直接使用java.exe命令来运行某个主类

类加载器

  类加载器

    负责将文件加载到内存中。并为之生成对应的Class对象

    虽然我们不需要关系类加载器原理,但是了解这个机制有利于我们更好的理解程序的运行

  类加载器的分类

    Bootstrap ClassLoader(根类加载器)

      也被称为引导加载器,负责java核心类的加载

        比如System、String等。在JDK中JRE的rt.jar中

    Extension ClassLoader(扩展类加载器)

      负责JRE的扩展目录中的jar包的加载

         在JDK中JRE中lib下的ext目录下

    System ClassLoader(系统类加载器)

      负责在JVM启动时加载来自java命令的class文件以及在classpath环境变量所指定的jar包和类路径

反射:

生成class对象:

package com.gz_01;

/*
 * 发射:通过class文件对象,使用该文件中的成员变量,构造方法,成员方法
 *
 * Person p=new Person();
 * p.使用
 *
 * 使用反射使用对应类中的方法,必须先的到该Class的文件对象,也就是得到Class类的对象
 * Class类:
 *         成员变量        Field
 *         构造方法        Constructor
 *         成员方法        Method
 *
 * 得到Class对象,三种方式:
 *     一个类的Class对象表示该类对应的Class文本对象。所以同一个类的Class类是相同的。在类元素前后不改变的情况下
 *         1、 Class<?> getClass()           返回此 Object 的运行时类。
 *         2、class        数据类型的静态方法
 *         3、static Class<?> forName(String className)          返回与带有给定字符串名的类或接口相关联的 Class 对象。
 *
 * 一般使用什么方法得到class对象呢?
 *         自己玩:随便用,类名.class.最方便
 *         开发:Class.forName(String className)
 *             为什么呢?因为开发中往往别人给你的是jar文件,所以使用对象.getClass可能行不通。不同人的类名可能相同,第二种方式也可能出问题,并且第三种方式还可以配置在配置文件中
 *
 * */
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException {
//        方式1:
        Person p=new Person();
        Class c1=p.getClass();
//        Person p2=new Person();
//        Class c2=p2.getClass();

//        方式2:
        Class c2=Person.class;
//        System.out.println(p==p2);

//        方式3:
        //java.lang.ClassNotFoundException //这里填写的是类名的全路径。如何正确书写类的全路径呢?
        //1、在外面一步一步从报名.子包名...类名,一步一步走过去
        //右键copy Qualified name
        Class c3=Class.forName("com.gz_01.Person");
        System.out.println(c1==c3);
    }
}

package com.gz_01;

public class Person {
    private String name;
    int age;
    public String address;

    public Person(){

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

    public void show(){
        System.out.println("show");
    }

    void method(String name,String address){
        System.out.println(name+"---"+address);
    }
    private String function(){
        return name+"---"+age;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", address=" + address
                + "]";
    }

}

Person.java

利用class对象得到构造:

package com.gz_02;

import java.lang.reflect.Constructor;

public class RefelectDemo01 {
    public static void main(String[] args) throws Exception {
        //得到反射的Class对象
        Class c=Class.forName("com.gz_01.Person");

        //我们希望通过该字节码对象使用该类的方法,所以我们如何生成该类的对象呢?构造方法
    // Constructor getConstructor(Class... parameterTypes) 返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定 公共构造 方法。
    // Constructor[] getConstructors() 返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。
    // Constructor getDeclaredConstructor(Class... parameterTypes) 返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。
    //Constructor[] getDeclaredConstructors()       返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。 

//        Constructor[] cor=c.getConstructors();//获取所有公共构造
//        Constructor[] cor=c.getDeclaredConstructors();//获取所有构造
//        for(Constructor cc:cor){
//            System.out.println(cc);
//        }
        Constructor cor=c.getConstructor();//获取指定构造 注意参数是类型Class文件的可变参
        //Constructor的方法
        // T newInstance(Object... initargs)  使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
        Object o=cor.newInstance();
        System.out.println(o);
        //做了上面这么多,相当于实现了这样一个功能
        //Object o=new Person();
    }

}
package com.gz_02;

import java.lang.reflect.Constructor;

//使用带参构造
//public Person(String name,int age,String address)
public class RefelectDemo02 {
    public static void main(String[] args) throws Exception {

        Class c=Class.forName("com.gz_01.Person");

        Constructor cor=c.getConstructor(String.class,int.class,String.class);

        Object o=cor.newInstance("林青霞",27,"北京");
        System.out.println(o);
    }
}
package com.gz_02;

import java.lang.reflect.Constructor;

//获取私有构造方法并使用
//private Person(String name)
public class RelectDemo03 {
    public static void main(String[] args) throws Exception {
        // Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。
        Class c=Class.forName("com.gz_01.Person");

        Constructor cor=c.getDeclaredConstructor(String.class);

        //IllegalAccessException 非法的访问异常  不能访问private修饰的

        //public void setAccessible(boolean flag)将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查。
        cor.setAccessible(true);//解除该对象的java访问检查
        Object o=cor.newInstance("刘亦菲");

        System.out.println(o);
    }
}

利用class对象得到成员变量:

package com.gz_03;

import java.lang.reflect.Field;

//需求:通过反射获取成员变量并使用
public class RefelcetDemo {
    public static void main(String[] args) throws Exception {

        Class c=Class.forName("com.gz_01.Person");
//           Field getDeclaredField(String name)
//         返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
//         Field[] getDeclaredFields()
//         返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。
//         Field getField(String name)
//         返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
//         Field[] getFields()
//         返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
//        Field[] ff=c.getFields();//public java.lang.String com.gz_01.Person.address
//        Field[] ff=c.getDeclaredFields();//private java.lang.String com.gz_01.Person.name int com.gz_01.Person.age public java.lang.String com.gz_01.Person.address
//        for(Field f:ff){
//            System.out.println(f);
//        }

//        /Field f=c.getField("name");//java.lang.NoSuchFieldException
//        Field f=c.getField("address");
        Field addressField=c.getDeclaredField("address");
//        System.out.println(addressField);
        //void set(Object obj, Object value)         将指定对象变量上此 Field 对象表示的字段设置为指定的新值。 

        //先新建一个对象,才能配合set方法使用
        Object o=c.getConstructor().newInstance();
//        System.out.println(o);
        addressField.set(o, "北京");
        System.out.println(o);

        //给name赋值private String name;
        Field nameField=c.getDeclaredField("name");
//        System.out.println(o);
        //java.lang.IllegalAccessException
        nameField.setAccessible(true);//去除java访问检查
        nameField.set(o, "林青霞");
        System.out.println(o);

        //给age赋值int age;
        Field ageField=c.getDeclaredField("age");
        //java.lang.IllegalAccessException
        ageField.setAccessible(true);
        ageField.setInt(o, 27);
        System.out.println(o);

    }
}

利用class对象得到成员方法:

package com.gz_04;

import java.lang.reflect.Method;

//通过反射获取成员方法并使用
public class RefelectDemo {
    public static void main(String[] args) throws Exception {

        Class c=Class.forName("com.gz_01.Person");
//         Method getDeclaredMethod(String name, Class<?>... parameterTypes)
//          返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
//         Method[] getDeclaredMethods()
//       返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
//       Method getEnclosingMethod()
//       如果此 Class 对象表示某一方法中的一个本地或匿名类,则返回 Method 对象,它表示底层类的立即封闭方法。
//       Method getMethod(String name, Class<?>... parameterTypes)
//          返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
//       Method[] getMethods()
//       返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。
//        Method[] ms=c.getMethods();
//        Method[] ms=c.getDeclaredMethods();//不包括继承的方法
//        for(Method m:ms){
//            System.out.println(m);
//        }
        Method showMethod=c.getMethod("show");
        //Object invoke(Object obj, Object... args)  对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。

        //来一个对象,带个参
        Object o=c.getConstructor(String.class,int.class,String.class).newInstance("林青霞",27,"北京");

        showMethod.invoke(o);

        Method functionMethod=c.getDeclaredMethod("function");
        //IllegalAccessException
        functionMethod.setAccessible(true);
        System.out.println(functionMethod.invoke(o));

    }
}

使用反射运行配置文件:

package com.gz_05;

import java.io.FileReader;
import java.lang.reflect.Method;
import java.util.Properties;

//使用反射运行配置文件
public class Test {
    public static void main(String[] args) throws Exception {
//        Student s=new Student();
//        s.love();
//        Teacher t=new Teacher();
//        t.Love();
//        Worker w=new Worker();
//        w.love();
        //使用反射,将配置文件放在class.txt里面
        Properties prop=new Properties();
        FileReader fr=new FileReader("src/class.txt");
        prop.load(fr);
        String className=prop.getProperty("className");
        String methodName=prop.getProperty("methodName");

        Class c=Class.forName(className);

        Object obj=c.getConstructor().newInstance();

        Method m=c.getMethod(methodName);
        m.invoke(obj);

    }

}
package com.gz_05;

public class Student {
    public void love(){
        System.out.println("爱生活,爱JAJA!");
    }

}
package com.gz_05;

public class Teacher {
    private String name;
    public void love(){
        System.out.println("爱生活,爱青霞!");
    }
    @Override
    public String toString() {
        return "Teacher [name=" + name + "]";
    }

}
package com.gz_05;

public class Worker {
    public void love(){
        System.out.println("爱生活,爱老婆!");
    }
}

class.txt
className=com.gz_05.Worker
methodName=love

使用反射越过泛型检查:

package com.gz_05;

import java.lang.reflect.Method;
import java.util.ArrayList;

//通过反射越过泛型检查
public class ArrayListDemo {
    public static void main(String[] args) throws Exception {
        ArrayList<Integer> al=new ArrayList<Integer>();
        al.add(10);
//        al.add("nihao");//报错了
        //我们知道,泛型只是编译期的一种检查限制的机制,其实在字节码文件中是不存在泛型的,查看源码,
        //我们发现在使用add()的参数是Object,add(10)世纪上是针对10包装成Integer类型然后add进去,通过反射,我们越过强制包装秤Integer
        Class c=al.getClass();
        Method add=c.getMethod("add", Object.class);
        add.invoke(al, "nihao");
        System.out.println(al.get(1));
    }
}
package com.gz_05;

import java.lang.reflect.Field;

/*
 * 写一个方法
 *     public void setProperty(Object obj,String propertyName,Object value){}将Object中名propertyName的属性赋值为value
 * */
public class Tool {
    public static void main(String[] args){
        Teacher t=new Teacher();
        setProperty(t, "name", "零");
        System.out.println(t);
    }
    public static void setProperty(Object obj,String propertyName,Object value){
        Class c=obj.getClass();
        try {
            Field p=c.getDeclaredField(propertyName);
            p.setAccessible(true);
            p.set(obj, value);
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

时间: 2024-10-07 17:43:55

类的加载到反射reflect的相关文章

类的加载和反射

一.类的加载 类的加载一共分为三步: 1.加载 就是将类加载进内存,并同时创建一个Class对象(就是描述一个 .class 文件的对象) 而且任何类被使用前都会先创建一个 Class对象 2.连接 验证 是否有正确的内部结构,并和其他类协调一致 准备 负责为类的静态成员分配内存,并设置默认初始化值 解析 将类的二进制数据中的符号引用替换为直接引用 3.初始化 见前面的初始化笔记. 初始化的时机: 创建类的实例 访问类的静态变量,或者为静态变量赋值 调用类的静态方法 使用反射方式来强制创建某个类

java 类的加载及反射机制

一,类的加载,连接,初始化 一个类被加载到JVM需要三个步骤:加载,链接,初始化 1,先说下加载过程 2,连接 注意连接过程分为三个阶段,验证,准备,解析 3,初始化 这里注意:类的加载过程,先加载静态代码块,其次是代码块,然后是构造函数 静态成员之间级别一样,因此谁在前,谁最先被加载 二,反射机制 1,先理解下反射 2,为什么要使用反射 可能以上叙述依然很抽象,下面我们用具题代码说明 在开始代码之前我们要先,明白一个对象 java.lang.Class 我们可以这样想,java程序在运行前,会

Java 学习 类的加载及反射

类加载机制与反射 (一)类的加载,连接和初始化 1,一个main函数相当于调用一个jvm进程,main函数结束其内存数据清除 2,类加载(类初始化)三个步骤:   1:类的加载: 2,类的连接: 3,类的初始化:                     (二)类加载器 1,Bootstrap ClassLoader:根类加载器(非ClassLoder子类,jvm提供) 2,Extension ClassLoader:扩展类加载器 负责加载JRE中的类 3,System ClassLoader:系

黑马程序员————java中类的加载、反射、动态代理、枚举

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- 类的加载.反射.动态代理.枚举 一.类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化. 1.加载: 就是指将class文件读入内存,并为之创建一个Class对象 ★★

类的加载、时机、反射、模板设计、jdk7/jdk8新特性(二十六)

1.类的加载概述和加载时机 * A:类的加载概述 * 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化. * 加载 * 就是指将class文件读入内存,并为之创建一个Class对象.任何类被使用时系统都会建立一个Class对象. * 连接 * 验证 是否有正确的内部结构,并和其他类协调一致 * 准备 负责为类的静态成员分配内存,并设置默认初始化值 * 解析 将类的二进制数据中的符号引用替换为直接引用 * 初始化 就是我们以前讲过的初始化

类的加载器和反射

类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化.  加载 就是指将class文件读入内存,并为之创建一个Class对象. 任何类被使用时系统都会建立一个Class对象   连接 验证 是否有正确的内部结构,并和其他类协调一致 准备 负责为类的静态成员分配内存,并设置默认初始化值 解析 将类的二进制数据中的符号引用替换为直接引用 类的初始化时机 1. 创建类的实例 2. 类的静态变量,或者为静态变量赋值 3. 类的静态方法 4

(反射)类的加载(33)

1.类的加载过程:加载.连接.初始化. 2.类的加载:将.class文件加载到内存中,并为之生成对应的class对象. 3.JRE System Librarys :运行时期 系统的类库. 4.java的反射机制:动态获取类的信息和动态调用类的方法的功能. 5.接口是个好东西,因为他可以约束实现接口的类的方法. 6.获取Class文件对象的三种方式(三种方式获取的Class都是同一个,也就是唯一性的):对象获取,类名获取,Class类的静态方法获取(Class = Class.forName("

java 反射,类的加载过程以及Classloader类加载器

首先自定义一个类Person package reflection; public class Person { private String name; public int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int a

跟王老师学反射(二):Java类的加载、连接和初始化

跟王老师学反射(二):Java类的加载.连接和初始化 主讲教师:王少华   QQ群号:483773664 学习内容: 了解类的加载.连接和初始化 一.类的生命周期 当我们编写一个java的源文件后,经过编译会生成一个后缀名为class的文件,这种文件叫做字节码文件,只有这种字节码文件才能够在java虚拟机中运行,java类的生命周期就是指一个class文件从加载到卸载的全过程.一个java类的完整的生命周期会经历加载.连接.初始化.使用.和卸载五个阶段,当然也有在加载或者连接之后没有被初始化就直