类的加载到反射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();
- }
- }
- }
类的加载到反射reflect的更多相关文章
- Java程序设计19——类的加载和反射-Part-B
接下来可以随意提供一个简单的主类,该主类无须编译就可使用上面的CompileClassLoader来运行它. package chapter18; public class Hello { publi ...
- Java程序设计19——类的加载和反射-Part-A
1 本文概要 本章介绍Java类的加载.连接和初始化的深入知识,并重点介绍Java反射相关的内容.本章知识偏底层点,这些运行原理有助于我们更好的把我java程序的运行.而且Java类加载器除了根加载器 ...
- 24.类的加载机制和反射.md
目录 1类的加载连接和初始化 1.1类的加载过程 1.2类的加载器 1.2.1类的加载机制 1类的加载连接和初始化 1.1类的加载过程 类的加载过程简单为分为三步:加载->连接->初始化 ...
- 类的加载、时机、反射、模板设计、jdk7/jdk8新特性(二十六)
1.类的加载概述和加载时机 * A:类的加载概述 * 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化. * 加载 * 就是指将class文 ...
- java 反射,类的加载过程以及Classloader类加载器
首先自定义一个类Person package reflection; public class Person { private String name; public int age; public ...
- java 27 - 1 反射之 类的加载器
说到反射,首先说类的加载器. 类的加载: 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化. 加载: 就是指将class文件读入内存,并为之 ...
- 反射 类的加载 Schema DOM 解析方式和解析器 命名空间
Day15 反射 1.1 类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化. l 加载 就是指将class文件读入内存,并为之创建 ...
- Java基础_类的加载机制和反射
类的使用分为三个步骤: 类的加载->类的连接->类的初始化 一.类的加载 当程序运行的时候,系统会首先把我们要使用的Java类加载到内存中.这里加载的是编译后的.class文件 每个类加载 ...
- Java反射——java.lang.Class和类的加载
反射的基础: java.lang.Class Class类的实例对象,用于记录类描述信息. 源码说:represent classes and interfaces in a running Java ...
随机推荐
- 图解 javascript 作用域链
还是之前那一段简单的javascript代码: window.onload=function(){ function sub(a,b){ return a-b; } var result=sub(10 ...
- HDU 1698 Just a Hook (线段树区间更新)
题目链接 题意 : 一个有n段长的金属棍,开始都涂上铜,分段涂成别的,金的值是3,银的值是2,铜的值是1,然后问你最后这n段总共的值是多少. 思路 : 线段树的区间更新.可以理解为线段树成段更新的模板 ...
- C# WINFORM 捕获全局异常
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Thr ...
- poj 3311(floyd+状态压缩)
题目链接:http://poj.org/problem?id=3311 思路:Floyd + 状态压缩DP 题意是有N个城市(1~N)和一个PIZZA店(0),要求一条回路,从0出发,又回到0,而且 ...
- JLink and JTAG等接口简介
1.JTAG JTAG用的计算机的并口,JTAG也是一种国际标准测试协议(IEEE 1149.1兼容),主要用于芯片内部测试.现在多数的高级器件都支持JTAG协议,如DSP.FPGA器件等. 标准的J ...
- keil MDK中如何生成*.bin格式的文件
在Realview MDK的集成开发环境中,默认情况下可以生成*.axf格式的调试文件和*.hex格式的可执行文件.虽然这两个格式的文件非常有利于ULINK2仿真器的下载和调试,但是ADS的用户更习惯 ...
- Centos环境下部署游戏服务器-SSH
在这个*nix大行其道的年代,SSH绝对值得你拥有,虽说它的语法真的很简单,可用途相当大.比如说你在登山,突然公司一个电话告诉你服务器出问题了,在登山的过程中,肯定不能背个几公斤的笔记本吧,这个时候只 ...
- FMX的综合评价
Cliff: 我个人觉得FMX值得学,因为可以做Mac软件,可以做Windows下的DirectUI,可以开发iOS/Android,而且是可视化开发,可利用RTL一切函数,包括可使用所有非可视控件. ...
- ThreadLocal的几种误区
最近由于需要用到ThreadLocal,在网上搜索了一些相关资料,发现对ThreadLocal经常会有下面几种误解 一.ThreadLocal是java线程的一个实现 ThreadLoca ...
- 281. Zigzag Iterator
题目: Given two 1d vectors, implement an iterator to return their elements alternately. For example, g ...