类的加载到反射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 ...
随机推荐
- zoj Fibonacci Numbers ( java , 简单 ,大数)
题目 //f(1) = 1, f(2) = 1, f(n > 2) = f(n - 1) + f(n - 2) import java.io.*; import java.util.*; imp ...
- HDU 1558 Segment set (并查集+线段非规范相交)
题目链接 题意 : 如果两个线段相交就属于同一集合,查询某条线段所属集合有多少线段,输出. 思路 : 先判断与其他线段是否相交,然后合并. #include <cstdio> #inclu ...
- 好玩的算法(JS版)
1.字符串反转 'cba'.split('').reverse().join(''); 2.在数组最后一位添加一项 array[array.length]=(new value);
- 网络安装之Redhat衍生版
GNU/Linux开源,这个意义实在是非常的广泛,目前在distrowatch上表现活跃的300个发行版代表了GNU/Linux的主流,然而细心的Linux爱好者会发现CentOS-based dis ...
- Android核心分析 之十一Android GWES之消息系统
Android GWES之Android消息系统 ...
- MyBatis学习总结_18_MyBatis与Hibernate区别
也用了这么久的Hibernate和MyBatis了,一直打算做一个总结,就他们之间的优缺点说说我自己的理解: 首先,Hibernate是一个ORM的持久层框架,它使用对象和我们的数据库建立关系,在Hi ...
- CentOS查看系统信息命令和方法
收集整理的一些linux查看系统信息的命令和方法: 一.linux查看服务器系统信息的方法: 1.查看主机名/内核版本/CPU构架: # uname -n -r -p -o localhost.loc ...
- Android 获取屏幕高度,宽度,状态栏高度
背景介绍: 到目前为止,android已经从1.5发展到目前的3.2,我们在写一个应用的时候,最常用到得就是获取屏幕高度,宽度,以及status bar的高度. 然而android系统变化太快了,从开 ...
- JSP的执行过程及其异常处理机制
1.JSP的执行过程 虽然JSP感觉上很像一般的HTML网页,但事实上它是以Servlet的形式被运行的.因为JSP文件在第一次运行的时候会先解释成Servlet源文件,然后编译成Servle ...
- 下载的时候如果文件名是中文就变成zip.zip
struts2 /WEB-INF/web.xml <?xml version="1.0" encoding="UTF-8"?> <web-ap ...