世界杯举办地_世界杯预选赛巴西 - emsxbc.com

java反射与映射(详解)

Java反射机制-

反射机制是什么

1、Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。 2、Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。

白话理解一下反射:

我们编译时知道类或对象的具体信息,此时直接对类和对象进行操作即可,无需使用反射(reflection)

如果编译不知道类或对象的具体信息,此时应该如何做呢?这时就要用到 反射 来实现。比如类的名称放在XML文件中,属性和属性值放在XML文件中,需要在运行时读取XML文件,动态获取类的信息

public class Test {

public static void main(String[] args) throws Exception {

//编码/编译的时候,已经知道要创建哪个类的对象,此时和反射没关系

//创建对象

//Animal an = new Dog();

Animal an = new Cat();

//操作属性

an.nickName ="旺财"; an.color = "黑色";

//执行方法

an.shout(); an.shout("门口");

an.run(); System.out.println(an);

//编码/编译的时候,不知道要创建哪个类的对象,只有根据运//行时动态获取的内容来创建对象

//使用Properties类读取属性文件,最终得到了类的完整路径字符串

String className = "com.bjsxt.why.Cat";

//创建对象

//Animal an2 = new "com.bjsxt.why.Cat"();

Class clazz = Class.forName(className);

Object an2 = clazz.newInstance();

//操作属性

//执行方法

}

}

反射的应用场合

在编译时根本无法知道该对象或类可能属于哪些类,程序只依靠运行时信息来发现该对象和类的真实信息

比如:log4j,Servlet、SSM框架技术都用到了反射机制

比如:log4j

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.logfile.layout=org.apache.log4j.PatternLayout

比如:Servlet

HelloServlet

servlet.HelloServlet

比如 SSM

class="org..jdbc.datasource.DataSourceTransactionManager">

反射的原理

下图是类的正常加载过程、反射原理与class对象:

Class对象的由来是将.class文件读入内存,并为之创建一个Class对象。

反射机制的优缺点

1、优点:

在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。

2、缺点:

(1)反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;

(2)反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

反射机制常用的类文件:

Java.lang.Class;

Java.lang.reflect.Constructor;

Java.lang.reflect.Field;

Java.lang.reflect.Method;

Java.lang.reflect.Modifier;

反射的作用

动态创建对象

动态操作属性

动态调用方法

在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中

Class类:代表一个类

Constructor 类:代表类的构造方法

Field 类:代表类的成员变量(属性)

Method类:代表类的成员方法

反射的入口—Class类

-Class类是Java 反射机制的起源和入口

用于获取与类相关的各种信息

提供了获取类信息的相关方法

Class类继承自Object类

-Class类是所有类的共同的图纸

每个类有自己的对象,好比图纸和实物的关系

每个类也可看做是一个对象,有共同的图纸Class,存放类的结构信息,比如类的名字、属性、方法、构造方法、父类和接口,能够通过相应方法取出相应信息

-Class类的对象称为类对象

代码演示:认知Class类

public class TestClass1 {

public static void main(String[] args) throws Exception {

//1.获取一个类的结构信息(类对象 Class对象)

Class clazz = Class.forName("com.bjsxt.why.Dog");

//2.从类对象中获取类的各种结构信息

//2.1 获取基本结构信息

System.out.println(clazz.getName());

System.out.println(clazz.getSimpleName());

System.out.println(clazz.getSuperclass());

System.out.println(Arrays.toString(clazz.getInterfaces()));

//2.2 获取构造方法

//只能得到public修饰的构造方法

//Constructor[] constructors = clazz.getConstructors();

//可以得到所有的构造方法

Constructor[] constructors = clazz.getDeclaredConstructors();

System.out.println(constructors.length);

for(Constructor con :constructors){

//System.out.println(con.toString());

System.out.println(con.getName() + "||" +

Modifier.toString(con.getModifiers())+" ||"

+ Arrays.toString(con.getParameterTypes()));

}

//Constructor con = clazz.getConstructor();//获取无参数构造方法

//Constructor con = clazz.getConstructor(String.class,String.class);

Constructor con =

clazz.getDeclaredConstructor(String.class,String.class);

System.out.println(con);

//2.3 获取属性

//Field[] fields = clazz.getFields();

Field [] fields = clazz.getDeclaredFields();

System.out.println(fields.length);

for(Field f :fields){

System.out.println(f);

}

//Field f = clazz.getField("color");

//private 默认 protecte public都可以获取,但不包括父类的

Field f = clazz.getDeclaredField("age");

System.out.println(f);

//2.3 获取方法

//Method[] methods = clazz.getMethods();

Method [] methods = clazz.getDeclaredMethods();

for(Method m : methods){

System.out.println(m);

}

//Method m = clazz.getMethod("shout",String.class);

//Method m = clazz.getMethod("run");//public

Method m = clazz.getDeclaredMethod("run");

System.out.println(m);

}

}

Class类的常用方法:

getFields()—— 获得类的public类型的属性。

getDeclaredFields()—— 获得类的所有属性

getField(String name)—— 获得类的指定属性

getMethods()—— 获得类的public类型的方法

getMethod (String name,Class [] args)—— 获得类的指定方法

getConstrutors()—— 获得类的public类型的构造方法

getConstrutor(Class[] args)—— 获得类的特定构造方法

newInstance()—— 通过类的无参构造方法创建对象

getName()—— 获得类的完整名字

getPackage()—— 获取此类所属的包

getSuperclass()—— 获得此类的父类对应的Class对象

获取一个类的类对象的三种方式:

public class TestClass2 {

public static void main(String[] args) throws Exception {

//1.获取一个类的结构信息(类对象 Class对象)

// 1.1Class.forName(类的完整路径字符串);

//Class clazz = Class.forName("java.lang.String");

//1.2 类名.class

// Class clazz = String.class;

//1.3 对象名.getClass()

String str = "bjsxt";

Class clazz = str.getClass();

//Integer in = new Integer(20);

//2.从类对象中获取类的各种结构信息

System.out.println(clazz.getName());

System.out.println(clazz.getSimpleName());

System.out.println(clazz.getSuperclass());

System.out.println(Arrays.toString(clazz.getInterfaces()));

}

}

其中类名.class、对象名.getClass()方式在编码时已经知道了要操作的类,而Class.forName()方式在操作的时候,可以知道,也可以不知道要操作的类。所以当编码时还不知道要操作的具体类,就只能使用Class.forName()方式了。

使用反射创建对象

调用无参数构造方法创建对象

方法1:通过Class的newInstance()方法

该方法要求该Class对象的对应类有无参构造方法

执行newInstance()实际上就是执行无参构造方法来创建该类的实例

方法2:通过Constructor的newInstance()方法

先使用Class对象获取指定的Constructor对象

再调用Constructor对象的newInstance()创建Class对象对应类的对象

通过该方法可选择使用指定构造方法来创建对象

代码示例:通过Class的newInstance()方法

public class TestConstructor1 {

public static void main(String[] args) throws Exception{

//不使用反射创建对象

//Dog dog = new Dog();

//使用反射创建对象

//1.获取类的完整路径字符串

String className = "com.bjsxt.why.Dog";

//2.根据完整路径字符串获取Class对象信息

Class clazz = Class.forName(className);

//3.直接使用Class的方法创建对象

Object obj = clazz.newInstance();

System.out.println(obj.toString());

}

}

代码示例:通过Constructor的newInstance()方法创建对象

public class TestConstructor2 {

public static void main(String[] args) throws Exception{

//不使用反射创建对象

//Dog dog = new Dog();

//使用反射创建对象

//1.获取类的完整路径字符串

String className = "com.bjsxt.why.Dog";

//2.根据完整路径字符串获取Class对象信息

Class clazz = Class.forName(className);

//3.获取无参数构造方法

Constructor con = clazz.getConstructor();

//4.使用无参数构造方法来创建对象

Object obj = con.newInstance();

System.out.println(obj);

}

}

使用反射操作属性

通过Class对象的getFields()或者getField()方法可以获得该类所包括的全部Field属性或指定Field属性。Field类提供了以下方法来访问属性

getXxx(Object obj):获取obj对象该Field的属性值。此处的Xxx对应8个基本数据类型,如果该属性类型是引用类型则直接使用get(Object obj)

setXxx(Object obj,Xxx val):将obj对象的该Field赋值val。此处的Xxx对应8个基本数据类型,如果该属性类型是引用类型则直接使用set(Object obj, Object val)

setAccessible(Boolean flag):若flag为true,则取消属性的访问权限控制,即使private属性也可以进行访问

代码示例:使用反射操作属性

public class TestField {

public static void main(String[] args) throws Exception{

//不使用反射操作属

// Dog dog = new Dog();

// dog.nickName = "旺财";

// dog.age ="黑色";

// System.out.println(dog.nickName);

// System.out.println(dog.color);

//使用反射操作属性 实际操作中使用反射直接操作属性也不多

//1.获取类的完整路径字符串

String className = "com.bjsxt.why.Dog";

//2.得到类对象

Class clazz = Class.forName(className);

//3.使用反射创建对象

//Object dog = clazz.newInstance();

Object dog = clazz.getConstructor().newInstance();

//4.获取属性

Field f1 = clazz.getField("color");

//Field f2 = clazz.getField("age");

Field f2 = clazz.getDeclaredField("age");

//5.给属性赋值

f1.set(dog,"黑色1"); // dog.color ="黑色";

f2.setAccessible(true);//突破权限的控制

f2.set(dog,10);

//6.输出给属性

System.out.println(f1.get(dog)); //dog.color

System.out.println(f2.get(dog)); //dog.age

System.out.println(dog);

}

}

使用反射执行方法

通过Class对象的getMethods() 方法可以获得该类所包括的全部方法, 返回值是Method[]

通过Class对象的getMethod()方法可以获得该类所包括的指定方法, 返回值是Method

每个Method对象对应一个方法,获得Method对象后,可以调用其invoke() 来调用对应方法

Object invoke(Object obj,Object [] args):obj代表当前方法所属的对象的名字,args代表当前方法的参数列表,返回值Object是当前方法的返回值,即执行当前方法的结果。

代码示例:使用反射执行方法

public class TestMethod {

public static void main(String[] args) throws Exception{

//不使用反射执行方法

// Dog dog = new Dog();

// dog.shout();

// int result = dog.add(10,20);

// System.out.println(result);

//使用反射执行方法

//1.获取类的完整路径字符串

String className = "com.bjsxt.why.Dog";

//2.得到类对象

Class clazz = Class.forName(className);

//3.使用反射创建对象

//Object dog = clazz.newInstance();

Object dog = clazz.getConstructor().newInstance();

//4.获取方法

Method m1 = clazz.getMethod("shout");

Method m2 = clazz.getMethod("add",int.class,int.class);

//5.使用反射执行方法

m1.invoke(dog);//dog.shout();

Object result = m2.invoke(dog,10,20);

System.out.println(result);

}

}

映射是一个数学概念,用于描述两个集合之间元素的对应关系。在映射中,每个输入元素都与一个输出元 素相关联。 可以将映射想象为一种规则或函数,它将集合A的每个元素映射到集合B的一个元素上。映射通常表示为箭 头符号或函数符号,例如"f: A → B",其中f表示映射的名称,A为输入集合,B为输出集合。 要理解映射的概念,可以使用实际例子进行说明。假设有两个集合:A = {1, 2, 3}和B = {a, b, c}。现在我 们定义一个映射f,它将A中的每个元素映射到B中的一个元素上。例如,我们可以定义f(1) = a,f(2) = b,f(3) = c。这样,我们就建立了A和B之间的映射关系。 通过映射,我们可以根据给定的输入找到相应的输出。例如,在上面的例子中,如果我们给定输入2,则根 据映射f,我们可以得出输出为b。 总结来说,映射是描述两个集合之间元素对应关系的概念,它将输入集合的每个元素映射到输出集合的一 个元素上