Java基础00-反射35
1. 类加载器
1.1 类加载
类加载或类初始化的三个步骤:类的加载、类的连接、类的初始化
加载:类加载过程的一个阶段:通过一个类的完全限定查找此类字节码文件,并利用字节码文件创建一个Class对象
验证:目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求,不会危害虚拟机自身安全。主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证。
准备:为类变量(即static修饰的字段变量)分配内存并且设置该类变量的初始值即0(如static int i=5;这里只将i初始化为0,至于5的值将在初始化时赋值),这里不包含用final修饰的static,因为final在编译的时候就会分配了,注意这里不会为实例变量分配初始化,类变量会分配在方法区中,而实例变量是会随着对象一起分配到Java堆中。
解析:主要将常量池中的符号引用替换为直接引用的过程。符号引用就是一组符号来描述目标,可以是任何字面量,而直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。有类或接口的解析,字段解析,类方法解析,接口方法解析(这里涉及到字节码变量的引用,如需更详细了解,可参考《深入Java虚拟机》)。
初始化:类加载最后阶段,若该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化成员变量(如前面只初始化了默认值的static变量将会在这个阶段赋值,成员变量也将被初始化)。
当一个类被载入了JVM,就不会被再次载入了,只载入一次。
1.2 类加载器
代码示例:
public class ClassLoaderDemo {
public static void main(String[] args) {
// static ClassLoader getSystemClassLoader (): 返回用于委派的系统类加载器
ClassLoader c = ClassLoader.getSystemClassLoader();
System.out.println(c); // AppClassLoader // ClassLoader getParent (): 返回父类加载器进行委派
ClassLoader c2 = c.getParent();
System.out.println(c2); // ExtClassLoader ClassLoader c3 = c2.getParent();
System.out.println(c3); // null
}
}
运行结果:
AppClassLoader:系统类加载器(System)
ExtClassLoader:平台类加载器(Platform)
null:内置类加载器(Bootstrap),所以它控制台输出为null
2. 反射
2.1 反射概述
深入理解反射机制
Student和Teacher,要想使用就要通过类加载器加载对象的.class文件到内存中去,而每一个.class文件中都应该包含,成员变量、构造方法、成员方法等,每个class文件都包含这些信息,而Class就是所有.class文件对应的类型,Class就可以使用,成员变量、构造方法、成员方法等,就不需要Student和Teacher了,这就叫反射。
2.2 获取Class类的对象
第一个方法比较简洁,
第三个方法比较的灵活,
一般使用推荐使用第三个方法。
代码示例:
获取Class类的对象就要有一个对象,所以要创建一个学生类
学生类:
public class Student {
// 成员变量,一个私有,一个默认,一个公共
private String name;
int age;
public String address; // 构造方法,一个私有,一个默认,两个公共
public Student() {
super();
} private Student(String name) {
super();
this.name = name;
} Student(String name, int age) {
super();
this.name = name;
this.age = age;
} public Student(String name, int age, String address) {
super();
this.name = name;
this.age = age;
this.address = address;
} // 成员方法,一个私有,四个公共
private void function() {
System.out.println("function");
} public void method1() {
System.out.println("method");
} public void method2(String s) {
System.out.println("method:" + s);
} public String method3(String s, int i) {
return s + "," + i;
} @Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", address=" + address + "]";
}
}
测试类:
//三种方式获取Class对象
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 1:使用类的class属性来获取该类对应的Class对象。举例: Student. class将会返回Student类对应的Class对象
Class<Student> c1 = Student.class;
System.out.println(c1); Class<Student> c2 = Student.class;
System.out.println(c1 == c2); // 一个类在内存中只有一个字节码文件对象,所以输出为true System.out.println("---------------------"); // 2:调用对象的getClass()方法,返回该对象所属类对应的Class对象
// 该方法是Object类中的方法,所有的Java对象都可以调用该方法
Student s = new Student();
Class<? extends Student> c3 = s.getClass();
System.out.println(c1 == c3);// 如果是true就代表通过该方法也可以得到该类的字节码文件 System.out.println("---------------------"); // 3:使用Class类中的静态方法forName(String className), 该方法需要传入字符串参数,该字符串参数的值是某个类的全路径
Class<?> c4 = Class.forName("myRrflect01.Student");
System.out.println(c1 == c4);// 如果是true就代表通过该方法也可以得到该类的字节码文件 }
}
运行结果:
2.3 反射获取构造方法并使用
代码示例:
对象使用的是2.2中的Student学生类
首先通过forName()得到字节码文件Class对象,通过Class对象的getConstructor()得到单个的构造方法,然后通过构造方法的newInstance()方法得到它的构造方法来创建对象。这就是反射。
public class ReflectDemo01 {
public static void main(String[] args) throws Exception {
// 获取Class对象
Class<?> c = Class.forName("myRrflect01.Student"); // Constructor<?>[] getConstructors():返回所有公共构造方法对象的数组
Constructor<?>[] cons1 = c.getConstructors();
for (Constructor<?> con1 : cons1) {
System.out.println(con1);
} System.out.println("------------------"); // Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组
Constructor<?>[] cons2 = c.getDeclaredConstructors();
for (Constructor<?> con2 : cons2) {
System.out.println(con2);
} System.out.println("------------------"); // Constructor<T> getConstructor(Class<?> .. parameterTypes):返回单个公共构造方法对象
// Constructor<T> getDeclaredConstructor(Class<?... parameterTypes):返回单个构造方法对象
// 参数:你要获取的构造方法的参数的个数和数据类型对应的字节码文件对象 // 取一个无参构造方法
Constructor<?> con = c.getConstructor();// 因为是无参,所以不需要添加参数。 // Constructor提供了一个类的单个构造函数的信息和访问权限
// Constructor类中用于创建对象的方法
// T newlnstance(Object... initargs):根据指定的构造方法创建对象
Object obj = con.newInstance();
System.out.println(obj ); // 这是不适用反射的方法
// Student s = new Student();
// System.out.println(s);
}
}
运行结果:
2.4 反射获取构造方法并使用练习
2.4.1 练习1
代码示例:
对象使用的是2.2中的Student学生类
//通过反射实现如下的操作:
//Student s = new Student("林青霞”, 30, "西安");
//System. out. println(s); public class RefectDemo02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// 获取Class对象
Class<?> c = Class.forName("myRrflect01.Student"); // 获取构造方法对象
// public Student(String name, int age, String address)
// Constructor<T> getConstructor (Class<?>... parameterTypes ),返回单个公共构造方法对象
// 基本数据类型也可以通过. class得到对应的Class类型
Constructor<?> con = c.getConstructor(String.class, int.class, String.class); // 利用构造方法得到对象
// T newInstance (object... initargs),根据指定的构造方法创建对象
Object obj = con.newInstance("林青霞", 30, "西安");
System.out.println(obj); }
}
2.4.2 练习2
代码示例:
对象使用的是2.2中的Student学生类
//通过反射实现如下的操作:
//Student s = new Student("林青霞");
//System. out. println(s);
public class RefectDemo03 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// 获取Class对象
Class<?> c = Class.forName("myRrflect01.Student"); // 获取构造方法对象
// private Student(String name)
// Constructor<T> getDeclaredConstructor (Class<?>... parameterTypes),返回单个构造方法对象
Constructor<?> con = c.getDeclaredConstructor(String.class); // 因为私有的构造方法是不能创建对象的,但是在反射里面是可以的,这就需要使用暴力反射
// public void setAccessible (boolean flag) :值为true,取消访问检查
con.setAccessible(true); // 利用构造方法得到对象
// T newInstance (object... initargs),根据指定的构造方法创建对象
Object boj = con.newInstance("林青霞");
System.out.println(boj);
}
}
运行结果:
2.5 反射获取成员变量并使用
代码示例:
首先获取Class对象,通过Class对象的getFields ()方法获取指定的成员变量,得到成员变量对象,通过成员变量对象调用set()方法,给对象的成员变量赋值。
对象使用的是2.2中的Student学生类
//反射获取成员变量并使用
public class ReflectDemo02 {
public static void main(String[] args)
throws ClassNotFoundException, NoSuchFieldException, SecurityException, NoSuchMethodException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// 获取Class对象
Class<?> c = Class.forName("myRrflect01.Student"); // Field[] getFields ()返回一个包含Field对象的数组,Field对象反 映由该Class对象表示的类或接口的所有可访问的公共字段
Field[] fields = c.getFields();
for (Field field : fields) {
System.out.println(field);
} System.out.println("----------------"); // Field[] getDeclaredFields () 返回一个Field对象的数组,反映了由该Class对象 表示的类或接口声明的所有字段
Field[] fields2 = c.getDeclaredFields();
for (Field field2 : fields2) {
System.out.println(field2);
} System.out.println("----------------"); // Field getField (String name) 返回一个Field对象, 该对象反映由该Class对象表示的类或接口的指定公共成员字段
// Field getDeclaredField (String name)返回个Field对象, 该对象反映由该Class对象 表示的类或接口的指定声明字段
Field addressField = c.getField("address"); // 获取无参构造方法获取对象
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance(); // Field提供有关类或接口的单个字段的信息和动态访问
// void set (object obj, object value) 将指定的对象参数中由此Field对象表示的字段设置为指定的新值
addressField.set(obj, "西安");// 给obj的成员变量addressField赋值为西安
System.out.println(obj); }
}
运行结果:
2.5.1 反射获取成员变量并使用练习
代码示例:
对象使用的是2.2中的Student学生类
public class ReflectDemo02 {
public static void main(String[] args)
throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
// 获取Class对象
Class<?> c = Class.forName("myRrflect01.Student"); // 获取无参构造方法创建对象
// Student s = new Student( );
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
System.out.println(obj); // s. name ="林青霞”;
// 因为name变量是私有的,所以使用getDeclaredField()方法获取,同时也要使用暴力反射setAccessible()方法为true
Field nameField = c.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj, "林青霞");
System.out.println(obj); // 为了方便也可以每次使用getDeclaredField()获取变量和setAccessible(true);取消访问检查 // s.age = 30;
Field ageField = c.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(obj, 30);
System.out.println(obj); // s. address = “西安”;
Field addressField = c.getDeclaredField("address");
addressField.setAccessible(true);
addressField.set(obj, "西安");
System.out.println(obj); }
}
运行结果:
2.6 反射获取成员方法并使用
首先获取Class对象,然后通过getMethod()方法得到成员方法对象,最后通过成员方法对象调用invoke()方法传入对象,就是调用该对象的方法。
代码示例:
对象使用的是2.2中的Student学生类
//反射获取成员方法并使用
public class ReflectDemo03 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// 获取Class对象
Class<?> c = Class.forName("myRrflect02.Student"); // Method[] getMethods() 返回一个包含方法对象的数组
// 方法对象反射由此表示的类或接口的所有公共方法 类对象,包括那些由类或接口和那些从超类和超接口继承的声明。
Method[] methods1 = c.getMethods();
for (Method method1 : methods1) {
System.out.println(method1);
} System.out.println("---------------------"); // Method[] getDeclaredMethods() 返回一个包含方法对象的数组
// 方法对象反射的类或接口的所有声明的方法,通过此表示类对象,包括公共,保护,默认(包访问和私有方法,但不包括继承的方法。
Method[] methods2 = c.getDeclaredMethods();
for (Method method2 : methods2) {
System.out.println(method2);
} System.out.println("---------------------"); // Method getMethod(String name, 类<?>... parameterTypes)
// 返回一个 方法对象,它反映此表示的类或接口的指定公共成员方法 类对象。
// Method getDeclaredMethod(String name, 类<?>... parameterTypes)
// 返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 类对象。 // 获取public void method1()
Method m = c.getMethod("method1"); // 获取无参构造方法创建对象
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance(); // 在类或接口.上提供有关单一方法的信息和访问权限
// Object invoke (Object obj, Object... args) 在具有指定参数的指定对象.上调用此方法对象表示的基础方法
// Object:返回值类型
// obj:调用方法的对象
// args:方法需要的参数
m.invoke(obj); }
}
运行结果:
最后输出了Student类中method1()成员方法
2.6.1 反射获取成员方法并使用练习
代码示例:
对象使用的是2.2中的Student学生类
public class ReflectDemo04 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// 获取Class对象
Class<?> c = Class.forName("myRrflect02.Student"); // Student s = new Student();
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance(); // s.method1();
Method m1 = c.getMethod("method1");
m1.invoke(obj); // s.method2( "林青霞");
Method m2 = c.getMethod("method2", String.class);
m2.invoke(obj, "林青霞"); // String ss = s. method3("林青霞", 30);
// System.out.println(ss);
Method m3 = c.getMethod("method3", String.class, int.class);
Object method3 = m3.invoke(obj, "林青霞", 30);
System.out.println(method3); // s.function();
// 这是一个私有方法,所以使用getDeclaredMethod()获取和setAccessible(true);取消访问检查
Method m4 = c.getDeclaredMethod("function");
m4.setAccessible(true);
m4.invoke(obj); }
}
运行结果:
2.9 反射练习
2.9.1 练习1
向integer集合中添加字符串类型的数据,原本是不可能实现的,但是在反射中是可以的。
代码示例:
public class ReflectTest01 {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
// 创建集合
ArrayList<Integer> array = new ArrayList<Integer>(); // 获取集合的Class对象
Class<? extends ArrayList> c = array.getClass(); // 调用集合Class对象的add方法
Method m = c.getMethod("add", Object.class); // 添加数据
m.invoke(array, "hello");
m.invoke(array, "world");
m.invoke(array, "java"); System.out.println(array);
}
}
运行结果:
2.9.2 练习2
这样使用灵活性较强
代码示例:
学生(Student)类:
public class Student {
public void study() {
System.out.println("好好学习,天天向上");
}
}
教师(Teacher)类:
public class Teacher {
public void teach() {
System.out.println("用爱成就学生");
}
}
配置文本:
class.text
测试类:
public class ReflectTest02 {
public static void main(String[] args)
throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { // 加载数据
Properties prop = new Properties();
FileReader fr = new FileReader("src\\myRrflect03\\class.text");
prop.load(fr);
fr.close(); // className=myRrflect03.Student
// methodNmae=study
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodNmae"); // 通过反射来使用
Class<?> c = Class.forName(className);// myRrflect03.Student Constructor<?> con = c.getConstructor();
Object obj = con.newInstance(); Method m = c.getMethod(methodName);// study
m.invoke(obj); }
}
运行结果:
修改配置类运行:
Java基础00-反射35的更多相关文章
- 黑马程序员:Java基础总结----反射
黑马程序员:Java基础总结 反射 ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 反射 反射的基石:Class类 Class类代表Java类,它的各个实例对象又分别 ...
- Java基础之一反射
反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)) 一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...
- Java基础之—反射
反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)) 一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...
- JAVA基础知识|反射
一.理解反射 1.1.基础概念 反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为ja ...
- java基础之反射机制
一.概念 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为jav ...
- Java基础(00)
Java发展史 Java之父:詹姆斯.高斯林(James Gosling). SUN(Stanford University Network 斯坦福大学网络公司)产物. 1995年5月23日,java ...
- java基础(十一 )-----反射——Java高级开发必须懂的
本文我们通过一个实际的例子来演示反射在编程中的应用,可能之前大家对反射的学习,仅仅是停留在概念层面,不知道反射究竟应用在哪,所以是一头雾水.相信通过这篇教程,会让你对反射有一个更深层次的认知. 概念 ...
- java基础之反射---重要
java反射: 反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)): 1:获取Class字节码文件对象的三种方式: /** ...
- 【Java基础】反射和注解
前言 在Java中,反射机制和注解机制一直是一个很重要的概念,那么他们其中的原理是怎么样呢,我们不仅仅需要会使用,更要知其然而之所以然. 目录 反射机制 反射如何使用 注解定义 注解机制原理 注解如何 ...
- java基础篇---反射机制
一.JAVA是动态语言吗? 一般而言,说到动态言,都是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,JAVA和C++一样,都不是动态语言. 但JAVA它却有着一个非常突出的动态相关机制:反 ...
随机推荐
- cmodel模拟器开发
cmodel模拟器开发 对于一个公司来说,产品的设计周期就是生命线,一般来说都会在设计功能级仿真的c-model后直接转向RTL设计. 在目前的技术下,做cycle-by-cycle的设计和直接RTL ...
- TVM交叉编译和远程RPC
TVM交叉编译和远程RPC 本文介绍了TVM中使用RPC的交叉编译和远程设备执行. 使用交叉编译和RPC,可以在本地计算机上编译程序,然后在远程设备上运行它.当远程设备资源受到限制时(如Raspber ...
- 细粒度语义分割:ICCV2019论文解析
细粒度语义分割:ICCV2019论文解析 Fine-Grained Segmentation Networks: Self-Supervised Segmentation for Improved L ...
- Visual SLAM
Visual SLAM 追求直接SLAM技术,而不是使用关键点,直接操作图像强度的跟踪和映射. 作为直接方法,LSD-SLAM使用图像中的所有信息,包括边缘,而基于关键点的方法只能在拐角处使用小块.这 ...
- VTA:深度学习加速器堆栈
VTA:深度学习加速器堆栈 多功能Tensor加速器(VTA)是一个开放的,通用的,可定制的深度学习加速器,具有完整的基于TVM的编译器堆栈.设计VTA来展示主流深度学习加速器的最显着和共同的特征.T ...
- 用NVIDIA-TensorRT构造深度神经网络
用NVIDIA-TensorRT构造深度神经网络 Deploying Deep Neural Networks with NVIDIA TensorRT NVIDIA TensorRT是一个用于生产环 ...
- 在python_request 中 nb-log 日志模块的使用,应用到项目实际使用
一.安装 pip install nb-log pycham 中安装: 二.基本使用 2.1 pycham中调整设置控制台日志打印出的颜色 2.2 设置完成后去掉console弹出的颜色设置 2.3 ...
- 1482. 制作 m 束花所需的最少天数
2021-05-09 LeetCode每日一题 链接:https://leetcode-cn.com/problems/minimum-number-of-days-to-make-m-bouquet ...
- Django工作流
1.Django的处理流程(没有涉及到数据库层的操作) 1-1:URL组成 http://127.0.0.1:8000/index/(协议:/ip地址:端口/主机上的目录或文件地址) 1-2:URLc ...
- 07:JS(03)
BOM与DOM操作 # 截至目前为止 我们虽然已经学会了js语法 但是你会发现跟浏览器和html文件还是一点关系没有 """ BOM 浏览器对象模型 Browser Ob ...