java中获取se_JavaSE(十)之反射

开始接触的时候可能大家都会很模糊到底什么是反射,大家都以为这个东西不重要,其实很重要的,几乎所有的框架都要用到反射,增加灵活度。到了后面几乎动不动就要用到反射。

首先我们先来认识一下对象

学生----->抽象----->Student

表示学生   Student = .......

那我们的反射中的Class呢?

类型----->抽象----->Class(反射的入口破)

java.lang.class    表示java中的类型

Class c = Student.Class

Class c = int.Class

Class c =int[].Class

一、反射(Reflection)的概述

1.1、定义

反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法 对于任意一个对象,都能够调用它的任意一个方法和属性, 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

即:在"运行时",通过反射机制可以动态获得到和该类型相关的各种信息。

java通常是先有类后有对象,有对象就可以调用方法或属性。反射其实是通过Class对象来调用类里面的方法。

通过反射可以调用私有方法和私有属性。大部分框架都是运用反射原理。

1.2、Class类型     java.lang.Class类

Class是对java中所有类型的抽象。即一个Class类型对象可以表示出java中任意一种类型。每种类型在加载到内存后,内存中都会生产一个与之对应的Class类型对象(有且只有一个),用来表示该类型。

每个类型都有且只有一个Class类型对象与之对应,通过这个Class类型对象就可以获得到该类型中的各种信息。Class类是Java反射的入口.。

1)表示基本类型

Class c = int.class;

System.out.println(c.isPrimitive());//true

System.out.println(c.getName());//int

注:其他基本类型的情况类似

2)表示类类型

注:s.getClass()方法返回的是变量s所指向对象的实现类型的Class对象。

Student s = new Student();

Class c1 = s.getClass();

Class c2 = Student.class;

System.out.println(c1 == c2);//true

//p指向的对象实际类型是Student

Person p = new Student();

Class c1 = p.getClass();//c1表示Student类型

Class c2 = Person.class;//c2表示Person类型

System.out.println(c1 == c2);//false

3)表示接口类型

Action a = new Student();

Class c1 = a.getClass();//c1表示Student类型

Class c2 = Action.class;//c2表示Action类型

System.out.println(c1 == c2);//false

System.out.println(c2.isInterface());//true

4)表示数组类型

int[] a = new int[4];

Class c1 = a.getClass();

Class c2 = int[].class;

System.out.println(c1 == c2);//true

System.out.println(c1.isArray());//true

Class c3 = c1.getComponentType();//c3表示该数组是使用什么类型声明出来的

System.out.println(c3.getName());//int

Student[] a = new Student[4];

Class c1 = a.getClass();

Class c2 = Student[].class;

System.out.println(c1 == c2);//true

System.out.println(c1.isArray());//true

Class c3 = c1.getComponentType();//c3表示该数组是使用什么类型声明出来的

System.out.println(c3.getName());//com.briup.test.Student

1.3、获取一个类类型的Class对象的三种方式

想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到

我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。

1)使用Class类中的forName方法获得

Class clazz1 = Class.forName("全限定类名");  //通过Class类中的静态方法forName,直接获取到一个类的字节码文件对象,此时该类还是源文件阶段,并没有变为字节码文件。

这种方法很灵活,只需一个String类型参数即可,而String类型的数据改变起来很容易,注意该方法是会抛出异常。

2)使用类名获得

Class clazz2  = Person.class;    //当类被加载成.class文件时,此时Person类变成了.class,在获取该字节码文件对象,也就是获取自己, 该类处于字节码阶段。

3)使用对象调用getClass方法获得

Class clazz3 = p.getClass();    //通过类的实例获取该类的字节码文件对象,该类处于创建对象阶段。

getClass是Object中的final修饰的方法,每个对象都可以调用而且不能重写

注:以上三种方法获得的同一个对象(==比较),因为每个类型内存都有且只有一个Class类型对象。

1.4、反射机制中的常见类的含义

java.lang包下:

Class  类        对java中所有类型抽象而得来的

Package类        对java中所有包抽象而得来的

java.lang.reflect包下:

Modifier    类    对java中所有修饰符抽象而得来的

Field        类    对java中所有属性抽象而得来的

Method        类    对java中所有方法抽象而得来的

Constructor 类    对java中所有构造器抽象而得来的

Array        类    提供了对数组对象的动态访问

ParameterizedType接口  在反射中表示参数化类型

例如:List Point等这种带泛型的类型

二、反射机制获取类中的信息

2.1、使用Class类型对象获得类中的信息

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1.获得该类所处的包的信息

Student s= newStudent();

Class c=s.getClass();

System.out.println(c.getPackage().getName());2.获得该类的修饰符信息//每个修饰符对应一个int值//如果有多个修饰符则int值相加

Student s = newStudent();

Class c=s.getClass();

System.out.println(c.getModifiers());

System.out.println(Modifier.PUBLIC);

System.out.println(Modifier.FINAL);3.获得该类的名字

Student s= newStudent();

Class c=s.getClass();

System.out.println(c.getName());4.获得该类的父类的Class对象

Student s= newStudent();

Class c=s.getClass();//superclass表示其父类型的Class对象

Class superclass =c.getSuperclass();

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

例如:

Class c= Object.class;

Class superclass=c.getSuperclass();

System.out.println(superclass.getName());//运行报错,因为Object没有父类

例如://判断c1是不是c2的子类型//判断c3是不是c2的子类型

Class c1 = Student.class;

Class c2= Person.class;

Class c3= String.classSystem.out.println(c2.isAssignableFrom(c1));//true

System.out.println(c2.isAssignableFrom(c3));//false

5.获得该类所实现的接口类型的Class对象

Student s= newStudent();

Class c=s.getClass();

Class[] interfaces=c.getInterfaces();for(Class clazz:interfaces){

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

}

例如://判断c1是不是c2的实现类//判断c3是不是c2的实现类

Class c1 = Student.class;

Class c2= Action.class;

Class c3= String.classSystem.out.println(c2.isAssignableFrom(c1));//true

System.out.println(c2.isAssignableFrom(c3));//false

6.获得该类中所有的属性

Student s= newStudent();

Class c=s.getClass();

Field[] declaredFields=c.getDeclaredFields();for(Field f:declaredFields){

System.out.println(f.getModifiers());

System.out.println(f.getType().getName());

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

}

注:

getDeclaredFields()方法返回类中声明的属性,包括私有的

getFields()方法只返回类中public修饰的属性,包括继承的

例如://获得某个指定的属性(也包括私有属性)

Student s = newStudent();

Class c=s.getClass();

Field f= c.getDeclaredField("score");

System.out.println(f.getModifiers());

System.out.println(f.getType().getName());

System.out.println(f.getName());7.获得该类中所有的方法

Student s= newStudent();

Class c=s.getClass();

Method[] declaredMethods=c.getDeclaredMethods();for(Method m:declaredMethods){

System.out.println(m.getModifiers());

System.out.println(m.getReturnType().getName());

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

System.out.println(Arrays.toString(m.getParameterTypes()));

System.out.println(Arrays.toString(m.getExceptionTypes()));

}

注:

getDeclaredMethods()方法返回类中声明的方法,包括私有的

getMethods()方法只返回类中public修饰的方法,包括继承的

例如://获得某个指定的方法(也包括私有方法)

Student s = newStudent();

Class c=s.getClass();

Method m= c.getDeclaredMethod("print");

System.out.println(m.getModifiers());

System.out.println(m.getReturnType().getName());

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

System.out.println(Arrays.toString(m.getParameterTypes()));

System.out.println(Arrays.toString(m.getExceptionTypes()));8.获得该类中所有的构造器

Student s= newStudent();

Class c=s.getClass();

Constructor[] declaredConstructors=c.getDeclaredConstructors();for(Constructor con:declaredConstructors){

System.out.println(con.getModifiers());

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

System.out.println(Arrays.toString(con.getParameterTypes()));

System.out.println(Arrays.toString(con.getExceptionTypes()));

}

注:

getDeclaredConstructors()方法返回类中所有构造器

getConstructors()方法只返回类中public修饰的构造器

例如://获得某个指定的构造器(也包括私有构造器)

Student s = newStudent();

Class c=s.getClass();

Constructor con= c.getDeclaredConstructor(double.class);

System.out.println(con.getModifiers());

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

System.out.println(Arrays.toString(con.getParameterTypes()));

System.out.println(Arrays.toString(con.getExceptionTypes()));9.获得父类型中的泛型的真实类型

因为泛型类的泛型参数在编译期会被擦除,所以我们不能再运行期间直接拿到该泛型的实际类型,但是可以通过子类的Class对象来获取父类的泛型类型。

例如: 不通过子类不能获得泛型实际类型public class GenericTest{publicT name;publicS say(T t,S s){returns;

}

}

main:

GenericTest t = new GenericTest();

Class c=t.getClass();

Field field= c.getDeclaredField("name");

System.out.println(field.getType());

System.out.println(field.getGenericType());//输出结果:

classjava.lang.Object

T

System.out.println("-------------------------");

Method method= c.getMethod("say", Object.class,Object.class);

System.out.println(method.getReturnType());

System.out.println(method.getGenericReturnType());//输出结果:

classjava.lang.Object

S

System.out.println("-------------------------");

System.out.println(Arrays.toString(method.getParameterTypes()));

System.out.println(Arrays.toString(method.getGenericParameterTypes()));//输出结果:

[class java.lang.Object, classjava.lang.Object]

[T, S]

例如: 通过子类可以获得父类中泛型的实际类型public class GenericTest{publicT name;publicS say(T t,S s){returns;

}

}public class Sub entends GenericTest{}

main:

Class c= Sub.class;//获得父类类型,包含泛型参数信息

Type superType =c.getGenericSuperclass();//判断父类类型是不是属于ParameterizedType类型//ParameterizedType表示带泛型的类型

if(superType instanceofParameterizedType){//强转,并调用方法获得泛型参数的实例类型

ParameterizedType pt =(ParameterizedType)superType;

Type[] actualTypeArguments=pt.getActualTypeArguments();//循环遍历,并强转为Class类型,因为Type接口中没有任何方法

for(Type t:actualTypeArguments){

Class clazz=(Class)t;

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

}

}

例如: 通过子类可以获得实现接口中泛型的实际类型

Class c= Sub.class;

Type[] types=c.getGenericInterfaces();for(Type t:types){if(t instanceofParameterizedType){

ParameterizedType pt=(ParameterizedType)t;

Type[] actualTypeArguments=pt.getActualTypeArguments();for(Type type:actualTypeArguments){

Class clazz=(Class)type;

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

}

}

}10.获得类中的注解

使用反射也可以获得类中的注解.(在之后的内容在来了解)

Class类型获取对象类中信息

2.2、反射的常用操作

1 public classStudent{2 private longid;3 privateString name;4

5 private static intage;6

7 get/set8

9 public static voidsay(){10 System.out.println("say..");11 }

1)使用反射的方式调用构造器创建类的对象

默认方式:必须调用无参构造器Class c = Student.class;Student s = (Student)c.newInstance();通用方式:获得构造器对象,并调用该构造器注:getConstructor方法和newInstance方法的参数都是可变参数

例如:获得无参构造器并调用创建对象

Class c = Student.class;

Constructor constructor = c.getConstructor();

Student o = (Student)constructor.newInstance();

System.out.println(o);

例如:获得有参构造器并调用创建对象

Class c = Student.class;

Constructor constructor = c.getConstructor(long.class,String.class);

Student o = (Student)constructor.newInstance(1L,"tom");

System.out.println(o);2)使用反射的方式访问对象中的属性

例如:

Student s = new Student();

Class c = s.getClass();

Field[] declaredFields = c.getDeclaredFields();

for(Field f:declaredFields){

//设置私有属性可以被访问

f.setAccessible(true);

//判断属性是否为static,静态属性的访问不需要对象

if(Modifier.isStatic(f.getModifiers())){

System.out.println(f.getName() +" = "+f.get(null));

}else{

System.out.println(f.getName() +" = "+f.get(s));

}

}注:Field类中的get方法可以获得属性值,set方法可以给属性设置值。3)使用反射的方式调用对象中的方法

例如:

Student s = new Student();

Class c = s.getClass();

Method m1 = c.getMethod("setName",String.class);

//m1表示Student中的setName方法

//调用对象s中的m1方法,并且传参"tom"

//s.setName("tom");

m1.invoke(s, "tom");

Method m2 = c.getMethod("getName");

String name = (String)m2.invoke(s);

System.out.println("name = "+name);

//调用静态方法 不需要对象

Method m3 = c.getMethod("say");

m3.invoke(null);

4)使用反射的方式动态操作数组

注:

Object[] o1 = new int[1];//编译报错

long[]      o2 = new int[1];//编译报错

int[]     o3 = new int[1];//编译通过

Object[] o1 = new 任意引用类型[1];//编译通过

例如:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

//要求:传任意类型"数组",把数组长度扩大1倍并返回//注意这里不能收Object[],//因为Object[] o = new Integer[4];编译通过//但是Object[] o = new int[4]; 编译报错//那么使用Object类中就可以接收任意类型的数组了

public staticObject arrayCopy(Object obj){//代码

}

实现:public staticObject arrayCopy(Object obj){

Class c=obj.getClass();

Object newArray= null;if(c.isArray()){int len =Array.getLength(obj);

Class> type =c.getComponentType();

newArray= Array.newInstance(type, len*2);for(int i=0;i

Object value=Array.get(obj, i);

Array.set(newArray, i, value);

}

}returnnewArray;

}

数组长度扩大一倍

三、Class的API详解

3.1、通过字节码对象创建实例对象

2dc568509fe5a8708a34625a3a2225f3.png

3.2、获取指定构造器方法

constructor 如果没有无参构造,只有有参构造如何创建实例呢?看下面

365c331d53df115f3f5e9deefc0c96cb.png

总结上面创建实例对象:Class类的newInstance()方法是使用该类无参的构造函数创建对象, 如果一个类没有无参的构造函数, 就不能这样创建了,可以调用Class类的getConstructor(String.class,int.class)方法

取一个指定的构造函数然后再调用Constructor类的newInstance("张三",20)方法创建对象

获取全部构造方法

699689c27785fc551b98683591618311.png

3.3、获取成员变量并使用

Field对象

获取指定成员变量

6f92bd8258cb215e5daeda76074a638a.png

Class.getField(String)方法可以获取类中的指定字段(可见的), 如果是私有的可以用getDeclaedField("name")方法获取,通过set(obj, "李四")方法可以设置指定对象上该字段的值,

如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值

获取全部成员变量

d654306cdf83cb88063bc80a9ff714ed.png

3.4、获得方法并使用

Method

c25bc011704cfc7604161626e74885df.png

Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...)方法可以获取类中的指定方法,

如果为私有方法,则需要打开一个权限。setAccessible(true);

用invoke(Object, Object...)可以调用该方法,

跟上面同理,也能一次性获得所有的方法

d7500d299c68948a9b3161b7c2588665.png

3.5、获得该类的所有接口

Class[] getInterfaces():确定此对象所表示的类或接口实现的接口

返回值:接口的字节码文件对象的数组

3.6、获取指定资源的输入流

InputStream getResourceAsStream(String name)

return:一个 InputStream 对象;如果找不到带有该名称的资源,则返回 null

参数:所需资源的名称,如果以"/"开始,则绝对资源名为"/"后面的一部分。

四、两个实例来全面了解反射

实例1:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

package corejava.test;

import java.lang.reflect.Array;

import java.lang.reflect.Constructor;classA{private intid;private String name="Tom";private A(inta,String name){

id=a;

}

@OverridepublicString toString() {return "A [id=" + id + ", name=" + name + "]";

}

}public classTest1 {public staticObject createObject(String classname) throws Exception {

Class> name =Class.forName(classname);returncreateObject(name);

}public static Object createObject(Class>c) throws Exception{

Objectobject=null;try{object=c.newInstance();

}catch(InstantiationException e) {//如果此 Class 表示一个抽象类、接口、数组类、基本类型或 void;//或者该类没有 null 构造方法; 或者由于其他某种原因导致实例化失败。//2、数组类、基本类型 能够创建对象

if(c.isArray()){object=Array.newInstance(c.getComponentType(),5);

}else if(c.isPrimitive()){if(c == boolean.class){object=false;

}else if(c==void.class){throw new Exception(c.getName()+"不能创建对象!");

}else{object=0;

}

}else{//3、没有 null 构造方法

Constructor>[] constructors =c.getConstructors();if(constructors.length==0) throw new Exception(c.getName()+"没有Public构造器!");

Class>[] parameterTypes = constructors[0].getParameterTypes();

Object[] parameters=newObject[parameterTypes.length];for(int i=0;i

parameters[i]=createObject(parameterTypes[i]);

}object=constructors[0].newInstance(parameters);

}//1、其他某种原因、void、抽象类、接口时抛出异常

if(object==null)throw new Exception(c.getName()+"不能创建对象!");

}return object;

}public static voidmain(String[] args) throws Exception {

System.out.println(createObject(A.class));

System.out.println("ssss");//System.out.println(new String());//System.out.println("ssss");

}

}

实例1

实例2:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

package corejava.test;

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

import java.lang.reflect.Modifier;

import java.lang.reflect.Parameter;

import java.nio.file.spi.FileSystemProvider;

importstatic java.lang.System.out;

finalclassB{private intid;private String name="Tom";private static String mm="Tom";private B(inta,String name){

id=a;

}

@OverridepublicString toString() {return "B [id=" + id + ", name=" + name + "]";

}public intf(String name,A a){returnid;}

}public classTest2 {public static void printClass(Class>c) throws Exception{//1、包名;

out.println(c.getPackage()+";");//2、修饰符 +class+类名{

out.println(Modifier.toString(c.getModifiers())+

"class"+c.getSimpleName()+"{");//3、修饰符 +属性类型+属性名;

for(Field f:c.getDeclaredFields()){out.print("\t"+Modifier.toString(f.getModifiers())+

" "+f.getType().getSimpleName()+" "+f.getName());

f.setAccessible(true);if(Modifier.isStatic(f.getModifiers()))out.print("="+f.get(null));out.println(";");

}//4、修饰符 +类名+( 参数类型+参数名字){ }

for(Constructor>constructor:c.getDeclaredConstructors()){out.print("\t"+Modifier.toString(constructor.getModifiers())+" "+c.getSimpleName()+"(");

Parameter[] ps=constructor.getParameters();for(int i=0;i

+ps[i].getName());if(i

}out.println("){}");

}out.println();//5、修饰符 +返回类型+方法名++( 参数类型+参数名字){ }

for(Method m:c.getDeclaredMethods()){out.print("\t"+Modifier.toString(m.getModifiers())+" "+m.getReturnType().getSimpleName()+" "+m.getName()+"(");

Parameter[] ps=m.getParameters();for(int i=0;i

+ps[i].getName());if(i

}out.println("){}");out.println();

}//6、}

out.println("}");

}public static voidmain(String[] args) throws Exception {

printClass(Object.class);

}

}

实例2

觉得不错的“点个推荐”哦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值