黑马程序员——Java语言基础——10.反射
来源:互联网 发布:java 圆周率算法 编辑:程序博客网 时间:2024/04/28 05:29
------- android培训、java培训、期待与您交流! ----------
本节考点:
1-1 反射概述
反射是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法;对于任意一个对象,都只能都调用它的任意一个方法和属性,这种动态获取的信息、动态调用对象的方法的功能称为java 的反射机制。
反射其实就是动态加载一个指定的类,并获取该类中的所有的内容。而且将字节码文件封装成对象,
并将字节码文件中的内容都封装成对象,这样便于操作这些成员。就是把JAVA类中的各种成分反射成为相应的JAVA类
简单说:反射技术可以对一个类进行解剖。
反射的好处:大大的增强了程序的扩展性。
1-1-1 反射的基本步骤
1、获得Class对象,就是获取到指定的名称的字节码文件对象。
2、实例化对象,获得类的属性、方法或构造函数。
3、访问属性、调用方法、调用构造函数创建对象。
1-1-2 获取Class对象的方式
获取这个Class对象,有三种方式:
1:通过每个对象都具备的方法getClass来获取。弊端:必须要创建该类对象,才可以调用getClass方法。
2:每一个数据类型(基本数据类型和引用数据类型)都有一个静态的属性class。弊端:必须要先明确该类。
前两种方式不利于程序的扩展,因为都需要在程序使用具体的类来完成。
3:使用的Class类中的方法,静态的forName方法。
指定什么类名,就获取什么类字节码文件对象,这种方式的扩展性最强,只要将类名的字符串传入即可。
注意:字节码文件是唯一的,所以无论怎么获取,都是同一份字节码文件。
示例:
// 1. 根据给定的类名来获得 用于类加载String classname = "cn.itcast.reflect.Person";// 来自配置文件Class clazz = Class.forName(classname);//此对象代表Person.class// 2. 如果拿到了对象,不知道是什么类型 用于获得对象的类型Object obj = new Person();Class clazz1 = obj.getClass();// 获得对象具体的类型// 3. 如果是明确地获得某个类的Class对象 主要用于传参Class clazz2 = Person.class;
1-1-3 九个预定义Class实例对象
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该Class 对象。
基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void也表示为 Class 对象
1-2 反射的用法
1-2-1 创建对象
获取了字节码文件对象后,最终都需要创建指定类的对象:
创建对象的两种方式(其实就是对象在进行实例化时的初始化方式):
1,调用空参数的构造函数:使用了Class类中的newInstance()方法。
2,调用带参数的构造函数:先要获取指定参数列表的构造函数对象,然后通过该构造函数的对象的newInstance(实际参数) 进行对象的初始化。
综上所述,第二种方式,必须要先明确具体的构造函数的参数类型,不便于扩展。所以一般情况下,被反射的类,内部通常都会提供一个公有的空参数的构造函数。
String name="com.dsa.类名";//寻找该名称类文件,并加载进内存,并非产生class对象Class clazz=Class.forName(name);//产生该类的对象Object obj=clazz.newInstance();//得到某一个指定构造方法Constructor constructor= Class.forName("").getConstructor(String.class);//创建实例对象Object obj=constructor.newInstance("abc");
1-2-2 Constructor构造方法
代表某个类中的一个构造方法。
Constructor类的实例对象代表类的一个构造方法。
反射公共,私有和保护的构造方法:
反射公共的需要的方法是:getConstructor();
反射私有的需要的方法是:getDeclaredConstructor();
Constructor对象代表一个构造方法,Constructor对象有的方法:得到构造方法名字,得到所属于的类,产生实例对象。
得到某个类空参数构造方法,例:
Constructor constructor = Class.forName("java.lang.String").getConstructor();
得到某个类所有的构造方法,例:
Constructor [] constructors= Class.forName("java.lang.String").getConstructors();
得到某一个带参数的构造方法,例:
Constructor constructor =Class.forName("java.lang.String").getConstructor(StringBuffer.class);
注意:一个类有多个构造方法,用什么方式可以区分清楚想得到其中的哪个方法呢?根据参数的个数和类型,例如,Class.getMethod(name,Class... args)中的args参数就代表所要获取的那个方法的各个参数的类型的列表。重点:参数类型用什么方式表示?用Class实例对象。
1-2-3 成员变量的反射(Field类)
Field类代表反射某个类中的一个成员变量。问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,而该类的实例对象有多个,如果是与对象关联,那关联的是哪个对象呢?所以字段fieldAge代表的是Age的定义,而不是具体的Age变量。
(注意访问权限的问题)也就是说,定义的是类对象,而非对象的对象。
当我们需要对其操作的时候,需要确定是那个具体的对象。
示例:
package com.itheima.study; public class Person { <span style="white-space:pre"></span>public int age; <span style="white-space:pre"></span>private int height; <span style="white-space:pre"></span>public Person(int age,int height){ <span style="white-space:pre"></span>this.age=age; <span style="white-space:pre"></span>this.height=height; <span style="white-space:pre"></span>} } package com.itheima.study;import java.lang.reflect.Field;public class ReflectTest{ <span style="white-space:pre"></span>public static void main(String...args) throws Exception{ <span style="white-space:pre"></span>Person p = new Person(20,30); <span style="white-space:pre"></span>Field fieldAge = p.getClass().getField("age"); <span style="white-space:pre"></span>System.out.println(fieldAge.get(p)); <span style="white-space:pre"></span>} }
1-2-4 成员方法的反射(Method类)
Method类代表某个类中的一个成员方法得到类中的某一个方法:
例子:Method charAt =Class.forName("java.lang.String").getMethod("charAt",int.class);
调用方法:
通常方式:System.out.println(str.charAt(1));
反射方式:System.out.println(charAt.invoke(str, 1));
如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?
说明该Method对象对应的是一个静态方法。
反射各种使用示例:
class ReflectDemo{public static void main(String[] args)throws Exception{getMethod5();}//获取类的字节码文件,并创建对象public static void getMethod_1()throws Exception{String className = "Person";Class clazz = Class.forName(className);//知道了类的名字,通过forName方法获取Object obj = clazz.newInstance();//创建空参数构造函数的对象,等于new Person()System.out.println(obj);}//获取构造器对象public static void getMethod2()throws Exception{String className = "Person";Class clazz = Class.forName(className);Constructor cons = clazz.getConstructor(String.class,int.class);//获取指定构造函数的构造器Object obj = cons.newInstance("nishiabi",12);//通过构造器对象中的方法创建指定参数的Person对象,如同new Person(“shacha”,10);System.out.println(obj);}//暴力访问和获取字段对象public static void getMethod3()throws Exception{String className = "Person";Class clazz = Class.forName(className);String fieldName = "age";Field field = clazz.getDeclaredField(fieldName);//获取字段对象Object obj = clazz.newInstance();field.setAccessible(true);//取消权限检查field.set(obj,20);System.out.println(obj);}//非静态方法public static void getMethod4()throws Exception{String className = "Person";Class clazz = Class.forName(className);Object obj = clazz.newInstance();Method method = clazz.getMethod("sop1",String.class);//获取方法对象method.invoke(obj,"nihao");//调用非静态函数的方法,需要传入对象和实参}//使用静态方法public static void getMethod5()throws Exception{String className = "Person";Class clazz = Class.forName(className);//Object obj = clazz.newInstance();不用创建对象String methodName = "sop";Method method = clazz.getMethod(methodName,null);method.invoke(null,null);//不用写对象和参数}}
1-3 反射的使用
练习一:利用反射的思想设计程序
import java.util.*;import java.io.*;class NoteBookRun{public static void main(String[] args) throws Exception{NoteBook open = new NoteBook();open.run();//这样传统的接口方法太麻烦,需要反复修改代码才能做到程序的拓展,因此重新使用反射的思想来设计程序//建立配置文件File configFile = new File("temp\\usb.properties");if (!configFile.exists()){configFile.createNewFile();}//读取配置文件FileReader fr = new FileReader(configFile);//方法获取其中的信息,建立properties对象Properties prop = new Properties();prop.load(fr);System.out.println(prop);//因为Properties对象中不存在0角标,而是从1开始,所以为0会出现空指针异常for (int i=1; i<=prop.size(); i++){String className = prop.getProperty("usb"+i);Class clazz = Class.forName(className);USB usb = (USB)clazz.newInstance();open.useUSB(usb);}fr.close();}}class NoteBook{public void run(){System.out.println("NoteBook run");}public void useUSB(USB usb){if(usb != null){usb.open();usb.close();}}}////class MouseByUSB implements USB{public void open(){System.out.println("mouse open");}public void close(){System.out.println("mouse close");}}class KeyByUSB implements USB{public void open(){System.out.println("key open");}public void close(){System.out.println("key close");}}interface USB{void open();void close();}练习二:定义功能,可同时打印数组和一般数据
import java.lang.reflect.*;public class PrintArray { public static void main(String[] args) { //定义个功能,是数组就打印数组,是基本变量就打印数值 int[] a = {110, 112, 119}; sop(a); } private static void sop(Object obj) { //利用反射来判断,传入的类是什么类型 Class clazz = obj.getClass(); if (clazz.isArray()) { //是数组,取元素打印 int len = Array.getLength(obj);// 关键还是数组类,为我们提供了方法 for (int i = 0; i < len; i++) { System.out.print(Array.get(obj, i) + " "); } } else { //不是数组是变量,直接打印 System.out.println(obj); } }}
------- android培训、java培训、期待与您交流! ----------
- 黑马程序员——java基础---反射
- 黑马程序员——Java基础---反射
- 黑马程序员——Java基础--- 反射
- 黑马程序员——JAVA基础 反射
- 黑马程序员——Java基础---反射
- 黑马程序员——Java基础---反射
- 黑马程序员——Java基础---反射
- 黑马程序员——Java基础---反射
- 黑马程序员——Java基础---反射
- 黑马程序员——java基础---反射
- 黑马程序员——Java基础---反射
- 黑马程序员——JAVA基础------反射
- 黑马程序员——JAVA基础---反射
- 黑马程序员—JAVA基础—反射
- 黑马程序员——Java基础---反射
- 黑马程序员——Java基础--反射
- 黑马程序员——java基础---反射
- 黑马程序员——Java基础---反射
- 怎样消除电脑开机时按F1的现象
- C语言文件操作函数大全
- 我的面试经历
- 【密码学】传统密码:统计分析
- 贝茨视觉训练法 (Dr William Bates)方法
- 黑马程序员——Java语言基础——10.反射
- 在一个layout中保持button都是一样大小的
- Ubuntu10.04设置开机自动登入root帐户(不要密码登录)|| Ubuntu14.04root登录|| Ubuntu12.04root登录
- PHP接口继承及接口多继承详解
- [Android UI布局]android:gravit与android:layout_gravity的区别
- WEB 打印 LODOP
- 人工神经网络(Artificial Neural Networks)
- Java读取ini配置
- A == B ?(考虑小数)