黑马程序员—JAVA基础学习日记十——反射学习总结

时间:2022-10-20 00:42:59

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

  

      java高新技术反射部分,算是java的进阶学习,我感觉还是比较不易理解的,看了张老师的视频,特意边打边总结,以便以后查看和理解

反射的概念是由 Smith 在 1982 年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在 Lisp 和面向对象方面取得了成绩。其中 LEAD/LEAD++  、OpenC++  、MetaXa 和OpenJava 等就是基于反射机制的语言。最近,反射机制也被应用到了视窗系统、操作系统和文件系统中。

  在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。一般来说,反射系统除了满足开放性条件外还必须满足原因连接(Causally-connected)。所谓原因连接是指对反射系统自描述的改变能够立即反映到系统底层的实际状态和行为上的情况,反之亦然。开放性
和原因连接是反射系统的两大基本要素。
Java 中,反射是一种强大的工具。它使您能够创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代表链接。 反射允许我们在编写与执行时,使我们的程序代码能够接入装载到 JVM 中的类的内部信息,而不是源代码中选定的类协作的代码。这使反射成为构建灵活的应用的主要工具。但需注意的是:如果使用不当,反射的成本很高。
        Reflection  是  Java  程序开发语言的特征之一,它允许运行中的  Java  程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。Java  的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C  或者  C++  中就没有办法在程序中获得函数定义相关的信息。
第一部分
package reflect;
public class ReflectTest1 {
/**
*@description
*
*反射的初步例子展示
*1、类和对象的区别、类是从许许多多的对象中抽象提取出来的
*2、java应用程序分为编译阶段、运行期两个阶段
*3、编译阶段为编译器将java源代码编译成二进制字节码、运行期由java虚拟机将需要使用的java类字节码通
过类加载器加载到内存中
*4、java虚拟机通过加载到的字节码、在需要生成对象的时候通过字节码new出一个个的实例对象
*
*@param args
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws ClassNotFoundException {
//反射就是将java的各个成分映射成java类
//在java类的世界里有许多类比如String类、Integer类、StringBuffer类等等
//将这些类对象再抽象成一个Class类、包含类名、包名、接口、字段、方法等属性
//反射的基本使用方法
Java 反射笔记整理
String s1 = "hellojava";
Class c1 = s1.getClass(); //获得s1对象的类对象
Class c2 = String.class; //通过类.class方式获取类对象
Class c3 = Class.forName("java.lang.String"); //经常使用的方式获取String类对象
System.out.println(c1 == c2); //true
System.out.println(c2 == c3); //true
//System.out.println(c1.getClassLoader().getClass().getName());
//报错信息如下、原因为不是一个java对象、底层的bootstrap
//Exception in thread "main" java.lang.NullPointerException
//at reflect.ReflectTest.main(ReflectTest.java:43)
}
}
第二部分
在处理反射时安全性是一个较复杂的问题。反射经常由框架型代码使用,由于这一点,我们可能希望
框架能够全面接入代码,无需考虑常规的接入限制。但是,在其它情况下,不受控制的接入会带来严重的
安全性风险,例如当代码在不值得信任的代码共享的环境中运行时。
package reflect;
import java.lang.reflect.Field;
/**
* @author Administrator
* @path reflect
* @description
* @history
*/
public class ReflectTest2 {
//java反射就是将java类的各个成分映射成java类
//Class类中有个field属性、filed对应又映射成一个Field类
//下面演示字段反射使用反射、暴力反射使用方式
/**
*@description
*@param args
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws NoSuchFieldException
* @throws SecurityException
*/
public static void main(String[] args) throws IllegalArgumentException,
Java 反射笔记整理
IllegalAccessException, SecurityException, NoSuchFieldException {
Point p1 = new Point(1,2);
Point p2 = new Point(3,4);
Class claz = p1.getClass();
//提取出全部字段类对象、private定义的不行
Field[] field = claz.getFields();
for (int i = 0; i < field.length; i++) {
System.out.println(field[i].getType()); //获取类型
System.out.println(field[i].get(p1)); //获取作用在p1对象上的字段值
System.out.println(field[i].get(p2)); //获取作用在p2对象上的字段值
}
Field[] fields = claz.getDeclaredFields();
for(Field f:fields){ //for循环增强
System.out.println(f.getType()); // int
System.out.println(f.get(p1));
System.out.println(f.get(p2));
//报错信息如下
//Class reflect.ReflectTest2  can not access a member of class reflect.Point with
modifiers "private"
}
//暴力反射使用方式如下jdk1.5
Field field1 = claz.getDeclaredField("x");
field1.setAccessible(true); //设置为true
System.out.println(field1.get(p1)); //1
System.out.println(field1.get(p2)); //3
}
}
/**
* @author Administrator
* @path reflect
* @description
* @history
*/
class Point{
private int x;
public int y;
public Point(){
Java 反射笔记整理
}
public Point(int x,int y){
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
第三部分
package reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author Administrator
* @path reflect
* @description
* @history
*/
public class ReflectTest3 {
//反射构造器使用方式、通过反射、构造器方式实例化对象
//1、先通过字节码/类对象获取一个构造器对象,传入对应的参数描述类型
//2、通过构造器对象上的newInstance方法实例化出对象
//反射方法调用使用方式
//1、静态方法  2、非静态方法
Java 反射笔记整理
/**
*@description
*@param args
* @throws NoSuchMethodException
* @throws SecurityException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws IllegalArgumentException
*/
public  static  void  main(String[] args)  throws  SecurityException, NoSuchMethodException,
IllegalArgumentException, InstantiationException, IllegalAccessException,
InvocationTargetException {
Constructor con = Test.class.getConstructor(String.class);
Test result = (Test)con.newInstance("hello java");
Test result2 = (Test)con.newInstance("hello java2");
result.objectMethod(result.getS()); // hello java
result2.objectMethod(result2.getS()); // hello java2
Method method = Test.class.getMethod("staticMethod", String.class);
method.invoke(null, "hello java"); //hello java  第一个参数传入了null表示不和对象绑定
Method method2 = Test.class.getMethod("objectMethod", String.class);
method2.invoke(result, "hello java2");//hello java2  传入对象result、因为要调用对象方

//method2.invoke(null, "hello java2");//因为是对象方法所以要报错
/*Exception in thread "main" java.lang.NullPointerException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at reflect.ReflectTest3.main(ReflectTest3.java:43)*/
}
}
/**
* @author Administrator
* @path reflect
* @description
* @history
*/
Java 反射笔记整理
class Test{
private String s;
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
public Test(String s){
this.s = s;
}
public Test(){
// do nothing
}
//静态方法不和某个对象绑定的
public static void staticMethod(String s){
System.out.println(s.toString());
}
//对象方法是和对象绑定再一起的
public void objectMethod(String s){
System.out.println(s.toString());
}
}
第四部分
package reflect;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* @author Administrator
* @path reflect
* @description  演示例子、用反射的方式过滤字段操作代码
* @history
*/
public class ReflectTest4 {
//用来存储低分的对象list
private static List<Info> sexList = new ArrayList<Info>();
/**
*@description  
Java 反射笔记整理
*@param args
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
public static void main(String[] args) throws IllegalArgumentException,
IllegalAccessException {
//随意new出两个对象,将性别为女的改成男的
Info info1 = new Info();
info1.setSex("male");
Info info2 = new Info();
info2.setSex("female");
add2List(info1);
add2List(info2);
System.out.println(sexList.size()); //1
System.out.println(sexList.get(0).getSex()); //male
}
/**
*@description  进行删选操作
*@param obj
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
private static void add2List(Info obj) throws IllegalArgumentException,
IllegalAccessException{
Field[] fields = obj.getClass().getDeclaredFields();
//对所有字段进行遍历操作、提取有用的字段信息
for(Field f:fields){
f.setAccessible(true);
//进行判断操作
System.out.println(f.getType());//java.lang.String/java.lang.String
System.out.println(f.getName()); //username/sex
if(f.getType() == String.class && f.getName().equals("sex")){
if(f.get(obj).equals("female")){ //女性身份
f.set(obj, "male"); //改为男性
//add to list
sexList.add(obj);
}
}
}
}
Java 反射笔记整理
}
/**
* @author Administrator
* @path reflect
* @description
* @history
*/
class Info{
private String username; //用户昵称
private String sex; //性别
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
第五部分
Java  的反射机制是使其具有动态特性的非常关键的一种机制,也是在 JavaBean  中广泛应用的一种
特性。 运用 JavaBean  的最常见的问题是:根据指定的类名,类字段名和所对应的数据,得到该类的实例,
下面的一个例子演示了这一实现。
package reflect;
import java.lang.reflect.Method;
public class ReflectTest5 {
/**
* @description
* @param args
*/
public static void main(String[] args) {
Base base = getJavaBean("reflect.Person1", "setUsername","hellojava");
Java 反射笔记整理
//  进行向下转型、强制类型转换
Person1 p1 = (Person1) base;
System.out.println("p1.username = " + p1.getUsername());
Base base2 = getJavaBean("reflect.Person2", "setEmail","hellojava@java.com");
Person2 p2 = (Person2) base2;
System.out.println("p2.email = " + p2.getEmail());
}
/**
* @description  通过类全名、方法、参数值获得javabean实例对象方法实现
* @param beanName
* @param fieldSetter
* @param paraValue
* @return
*/
public static Base getJavaBean(String beanName,String setMehtod, String setValue) {
Base base = null; //  抽象基类
try {
Class cls = Class.forName(beanName);
//传入的javabean类必须要有个无参数的构造方法public权限的
base = (Base) cls.newInstance(); //  向上转型
Class[] paraTypes = new Class[] { String.class }; //参数类型数组
Method method = cls.getMethod(setMehtod, paraTypes);
method.invoke(base, setValue);
} catch (Throwable e) {
e.printStackTrace();
}
return base;
}
}
/**
* @author Administrator
* @path reflect
* @description
* @history
*/
abstract class Base {
//  定义抽象基类
}
Java 反射笔记整理
class Person1 extends Base {
private String username;
private String password;
/*public Person1(String username, String password) {
this.username = username;
this.password = password;
}*/
//通过字节码newInstance实例时候出现异常
//因为没有上面定义了新的带两个参数的构造方法
/*java.lang.InstantiationException: reflect.Person1
at java.lang.Class.newInstance0(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at reflect.ReflectTest5.convertStr2ServiceBean(ReflectTest5.java:35)
at reflect.ReflectTest5.main(ReflectTest5.java:12)*/
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
class Person2 extends Base {
private String realname;
private String email;
/*public Person2(String realname, String email) {
this.realname = realname;
this.email = email;
}*/
public String getRealname() {
return realname;
Java 反射笔记整理:
}
public void setRealname(String realname) {
this.realname = realname;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
总结如下:
Java 语言反射提供一种动态链接程序组件的多功能方法。它允许程序创建和控制任何类的对象(根据
安全性限制),无需提前硬编码目标类。这些特性使得反射特别适用于创建以非常普通的方式与对象协作的
库。例如,反射经常在持续存储对象为数据库、XML 或其它外部格式的框架中使用。
Java  reflection  非常有用,它使类和数据结构能按名称动态检索相关信息,并允许在运行着的程序中
操作这些信息。 Java  的这一特性非常强大,并且是其它一些常用语言,如  C、 C++、 Fortran  或者  Pascal
等都不具备的。
但反射有两个缺点。第一个是性能问题。用于字段和方法接入时反射要远慢于直接代码。性能问题的
程度取决于程序中是如何使用反射的。如果它作为程序运行中相对很少涉及的部分,缓慢的性能将不会是
一个问题。即使测试中最坏情况下的计时图显示的反射操作只耗用几微秒。仅反射在性能关键的应用的核
心逻辑中使用时性能问题才变得至关重要。
许多应用中更严重的一个缺点是使用反射会模糊程序内部实际要发生的事情。程序人员希望在源代码
中看到程序的逻辑,反射等绕过了源代码的技术会带来维护问题。反射代码比相应的直接代码更复杂,正
如性能比较的代码实例中看到的一样。解决这些问题的最佳方案是保守地使用反射——仅在它可以真正增
加灵活性的地方——记录其在目标类中的使用。
第六部分
#className=java.util.ArrayList
className=java.util.HashSet
package reflect;
//import java.io.File;
//import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Properties;
public class ReflectTest6 {
Java 反射笔记整理
/**
*  定义并实例化property实例对象
*/
private static Properties props = new Properties();
private static String className = null; //  加载的类名称
//  通过加载配置文件的方式进行加载资源文件
static {
//放在类路径下、如何采用相对路径呢
//    File file = new File("config.properties");
InputStream ips = null;
try {
//  面向接口编程文件输入流对象
//      ips = new FileInputStream(file);
//下面采用类加载加载配置文件方式处理
ips =
ReflectTest6.class.getClassLoader().getResourceAsStream("reflect/config.properties");
//reflect/config.properties采用相对路径
props.load(ips); //  进行装载处理
className = props.getProperty("className");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
//  关闭资源文件
try {
ips.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* @description
* @param args
* @throws ClassNotFoundException
* @throws IllegalAccessException
Java 反射笔记整理
* @throws InstantiationException
*/
public static void main(String[] args) throws ClassNotFoundException,
InstantiationException, IllegalAccessException {
//  进行测试分别模拟ArrayList和HashSet
Class claz = Class.forName(className);
Object obj = claz.newInstance(); //  通过字节码生成实例对象,并且向上转型
Collection<Person> collection = (Collection<Person>) obj; //  进行向下转型处理
Person p1 = new Person("java",'m',15);
Person p2 = new Person("java2",'w',10);
Person p3 = new Person("java",'m',15); //Person类覆写了equals和hashCode方法
collection.add(p1);
collection.add(p2);
collection.add(p3);
//p1,p3由于覆写了equals和hasCode方法,所以p1.equals(p3)
System.out.println("size = "+collection.size()); //ArrayList:3,HashSet:2
}
}
class Person {
private String username;
private char sex;
private int age;
//根基类Object的equals方法
/*public boolean equals(Object obj) {
return (this == obj);
}*/
public Person() {
//  无参数构造方法
}
public Person(String username, char sex, int age) {
super();
this.username = username;
this.sex = sex;
this.age = age;
}
Java 反射笔记整理
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + sex;
result = prime * result
+ ((username == null) ? 0 : username.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
Java 反射笔记整理
if (age != other.age)
return false;
if (sex != other.sex)
return false;
if (username == null) {
if (other.username != null)
return false;
} else if (!username.equals(other.username))
return false;
return true;
}
}
第七部分
package reflect;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
//import java.util.HashMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
public class ReflectTest7 {
/**
*@description  通过反射获取泛型参数的实际类型,在ORM框架用得比较多
*@param args
* @throws NoSuchMethodException
* @throws SecurityException
*/
public  static  void  main(String[] args)  throws  SecurityException,  NoSuchMethodException
{
//    通过反射获取泛型参数的类型
//    获取Map内泛型的参数类型、上例的String,Integer
//    说明、直接通过类对象没有办法直接获取、采用Method类对象提供的方法处理
//    Map<String,Integer> map = new HashMap<String,Integer>();
Method method = ReflectTest7.class.getMethod("apply", Map.class);
Type[] types = method.getGenericParameterTypes();
ParameterizedType pType = (ParameterizedType)types[0];
System.out.println(pType);
Java 反射笔记整理
System.out.println(pType.getRawType());
System.out.println(pType.getActualTypeArguments()[0]); //返回的是数组、取第一个值
System.out.println(pType.getActualTypeArguments()[1]);//取第二个值
//    java.util.Map<java.lang.String, java.lang.Integer>
//    interface java.util.Map
//    class java.lang.String
//    class java.lang.Integer
Type type = method.getGenericReturnType();
ParameterizedType pt = (ParameterizedType)type;
System.out.println(pt);
System.out.println(pt.getRawType());
System.out.println(pt.getActualTypeArguments()[0]);
//    java.util.Collection<java.lang.String>
//    interface java.util.Collection
//    class java.lang.String
}
/**
*  帮助获取泛型参数类型的方法实现
*@description
*@param map
*/
public static Collection<String> apply(Map<String,Integer> map){
Collection<String> list = new ArrayList<String>();
list.add("java");
return list;
}
}

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------