反射,是在java中非常有用,在框架中也经常接触的一种方法,所以反射是在开发中必须会的东西
所谓反射,就是给你一个XX.class文件,你通过反射方法,能够拿到该XX类相关的所有资源,比如该类所在位置,通过该类创建一个对象x,获取这个类X创建的对象x的所有公有、私有属性和公有、私有方法。这个技术你值得学习。
首先,我写了一个TestClass.java文件,作为编译成class后要使用的TestClass.class文件,然后ReflectDemo.java演示所有反射技术的demo,这里你将学会反射里常见的方法。先给大家一个方法总结,然后看代码,熟悉相关应用。
1、方法总结:
1.1获取class的三种方法:
第一种:Class clazz = Class.forName(XX.class的全包名)
第二种:Class clazz = XX xx = new XX();xx.getClass();
第三种:Class clazz = XX.class;
见实例代码test0()
1.2如何通过类class文件,拿到该文件里面的资源?这种方式获取的路径方法,永远是固定的,不会随着工程的路径改变而改变,始终都能获取到。
比如,TestClass.class文件(被编译后)所在的classes文件夹下,有prop.properties属性文件,如何拿到这个文件的绝对路径?如何把该文件加载到流中?通过在clazz中有个getClassLoader()方法,得到类加载器ClassLoader,然后再通过getSource()的方法,得到URL,然后再getPath()得到路径名
两种固定写法:
第一种:
Class clazz = TestClass.class;
ClassLoader classLoader = clazz.getClassLoader();
URL url = classLoader.getResource("prop.properties");
String path = url.getPath();
InputStream ins = new FileInputStream(path);
链式写法为:String path = TestClass.class.getClassLoader().getResource("prop.properties").getPath();
InputStream ins = new FileInputStream(path);
第二种[直接将资源加载成流]:InputStream ins = TestClass.class.getClassLoader().getSourceAsStream("prop.properties");
见实例代码test()
1.3如何用该class文件,创建一个对象?
创建对象有两种方法,直接用xx.newInstance()或使用xx.constructor()获取构造器然后再newInstance()。
第一种:
Class xx = TestClass.class;
Object obj = xx.newInstance();//无参构造方法
TestClass tc = (TestClass)obj;//转换为该类的对象
第二种:
Class xx = TestClass.class;
Constructor cst = xx.getConstructor();//无参构造方法
Object obj = cst.newInstance();//这个也不能有参数
TestClass tc = (TestClass)obj;//转换为该类的对象
见实例代码test1()、test2()
注意:这两种方法,只能使用无参的构造方法来创建无参默认的对象,如果想创建带参的对象呢?
使用构造器,然后指定参数类型,再创建实例对象时,将实参数传递
Class xx = TestClass.class;
Constructor cst = xx.getConstructor(String.class,int.class);//指定参数类型的带参构造方法
Object obj = cst.newInstance("李四",18);//顺便指定好实参
TestClass tc = (TestClass)obj;//转换为该类的对象
见实例代码test2()
1.4如何获取到该类创建的对象中的公有及私有属性值呢?需要用到xx.getField().get()或xx.getDeclaredField().setAccessible().get();
注意:获得公有私有的属性和方法时,必须指定获取哪个对象的,必须创建好一个对象。
Class xx = TestClass.class;
Constructor cst = xx.getConstructor(String.class,int.class);//指定参数类型的带参构造方法
Object obj = cst.newInstance("李四",18);//顺便指定好实参
TestClass tc = (TestClass)obj;//转换为该类的对象
//获取公有属性name:
Field fieldName = xx.getField("name");//指定哪个字段
Object name = fieldName.get(tc);//获取tc对象的name值
String strname = (String)name;
//获取私有属性age:
Field fieldAge = xx.getDeclaredField("age");//获取所有声明的一个叫age的字段
fieldAge.setAccessible(true);//使得该私有age可以被获取
Object age = fieldAge.get(tc)//获取tc的私有age
int intage = (int)age;
见实例代码test3()
1.5如何获取到该类创建的对象中的公有及私有的方法呢?xx.getMethod().invoke()或者xx.getDeclaredMethod().setAccessible().invoke();
注意:获得公有私有的属性和方法时,必须指定获取哪个对象的,必须创建好一个对象。
Class xx = TestClass.class;
Constructor cst = xx.getConstructor();//无参构造方法
Object obj = cst.newInstance();//这个也不能有参数
TestClass tc = (TestClass)obj;//转换为该类的对象
//获得公有的无参的方法:
Method mt1 = xx.getMethod("showPublic");//指定获取哪个方法(showPublic()方法)
mt1.invoke(tc);//获取对象tc中的showPublic()方法
//获得公有的带参的方法:
Method mt2 = xx.getMethod("showPublicParams", String.class,int.class);//指定获取哪个方法,并指定带哪种参数(showPublicParams(String,int)方法)
mt2.invoke(tc1, "刘二麻子",23);//获取对象tc中的showPublicParams并指定传进两个实参
//获得私有的无参方法【两步:1.获得声明的方法;2.让该方法可视化】
Method mt3 = xx.getDeclaredMethod("showPrivate");//获取哪个私有方法(showPrivate()方法)
mt3.setAccessible(true);//该方法可被获取,即可视化
mt3.invoke(tc);//获取对象tc中的showPrivate()方法
见实例代码test4()
1.6如果一个方法中的参数带了泛型,怎么获取该参数以及泛型参数的类型?如参数为(List,int)
见实例代码test5()。其中,getGenericParameterTypes 只能获取方法的参数列表中的类型,返回的是一个类型数组[list类型,int类型];ParameterizedType是Type的子接口,需要向下转型为ParameterizedType,然后再使用方法getActualTypeArguments获取泛型的参数类型,返回的是个类型数组[People类型,String类型]。
见实例代码test5()
2、实例代码:
TestClass.java的代码【有公有私有属性,有公有私有方法,有带返回值的方法,有带泛型的方法】如下:
package com.dou.reflect;
import java.util.List;
public class TestClass {
public String name = "张三";//公有属性
private int age = 28;//私有属性
public TestClass() {//带参构造
super();
// TODO Auto-generated constructor stub
}
public TestClass(String name, int age) {//满参构造
super();
this.name = name;
this.age = age;
}
public void showPublic() {//无参共有方法
System.out.println("这是无参共有方法showPublic()->" + this.name + ":" + this.age);
}
public void showPublicParams(String name, int age) {//带参公有方法
System.out.println("这是带参共有方法showPublicParams(String,int)->" + name + ":" + age);
}
public String showHello(){//带返回值公有无参方法
return "hello word";
}
public void showParameterized(List list,int num){//带泛型公有方法
for (String str : list) {
System.out.println(str+num);
}
}
private void showPrivate() {//无参私有方法
System.out.println("这是无参私有有方法showPrivate()->" + this.name + ":" + this.age);
}
}
//--------------
ReflectDemo.java的代码【常用反射方法】如下:
package com.dou.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import org.junit.Test;
public class ReflectDemo2 {
@Test
//获得带返回值的方法,以及参数类型和参数化的类型。如List的TestClass类型
public void test5() throws Exception {
Class clazz1 = TestClass.class;
TestClass tc1 = (TestClass)clazz1.newInstance();
Method m1 = clazz1.getMethod("showHello");
String str = (String) m1.invoke(tc1);
System.out.println(str);
//参数类型showParameterized(List list,int num)
Method m2 = clazz1.getMethod("showParameterized", List.class,int.class);
//获得你这个method对象(某个方法)的参数列表
Type[] types = m2.getGenericParameterTypes
();
for (Type type : types) {
System.out.println(type.toString());
//java.util.List
//int
}
//获得泛型的类型,ParameterizedType是Type的子接口,代表参数化类型
Type tp = m2.getGenericParameterTypes
()[0];//参数列表中的第一个参数
ParameterizedType ptp = (ParameterizedType)tp;
//getActualTypeArguments获得泛型参数列表里的泛型的类型
Type T_type = ptp.getActualTypeArguments()[0];//泛型里的第一个参数列表
System.out.println(T_type.toString());//class java.lang.String
}
@Test
//通过反射方法,获取类创建的对象中获取公有和私有方法
public void test4() throws Exception {
//showPublic/showPublicParams/showPrivate
Class clazz1 = TestClass.class;
TestClass tc1 = (TestClass)clazz1.newInstance();//创建一个被获取的对象
//获得公有的无参的方法
Method mt1 = clazz1.getMethod("showPublic");
mt1.invoke(tc1);
//获得公有的带参的方法
Method mt2 = clazz1.getMethod("showPublicParams", String.class,int.class);
mt2.invoke(tc1, "刘二麻子",23);
//获得私有的无参方法【两步:1.获得声明的方法;2.让该方法可视化】
Method mt3 = clazz1.getDeclaredMethod("showPrivate");//获取私有方法
mt3.setAccessible(true);//该方法可视化
mt3.invoke(tc1);
}
@Test
//通过反射方法,获取类中的公有属性和私有属性
public void test3() throws Exception {
Class clazz1 = TestClass.class;
//获取公有属性[需要一个获取哪个对象的实际对象]
Field f1 = clazz1.getField("name");
TestClass tc1 = (TestClass)clazz1.newInstance();
Object name1 = f1.get(tc1);
System.out.println("默认构造函数对象的公有属性name值:"+name1);
//想用带参的,则需要用constructor方法指定参数
Constructor cs1 = clazz1.getConstructor(String.class,int.class);
TestClass tc2 = (TestClass)cs1.newInstance("李四",18);
Field fl2 = clazz1.getField("name");
Object name2 = fl2.get(tc2);
System.out.println("带参构造函数对象的公有属性name值:"+name2);
//想获取私有的属性age【两步:1.获取私有属性方法getDeclaredField();2.将私有属性可视化setAccessible();】
Field fl3 = clazz1.getDeclaredField("age");//获取私有属性的特有方法
fl3.setAccessible(true);//将私有属性公开可视化的方法
Object age = fl3.get(tc2);
System.out.println("私有属性age的值:"+age);
}
@Test
//根据类文件,通过构造器getConstructor()创建对象,可以调用带参的构造方法创建带参的对象
public void test2() throws Exception {
Class clazz1 = TestClass.class;
//默认无参的构造方法创建对象
Constructor cc = clazz1.getConstructor();
TestClass tc1 = (TestClass)cc.newInstance();
tc1.showPublic();
//想调用有参的构造方法,创建带参的对象
Constructor cc2 = clazz1.getConstructor(String.class,int.class);
TestClass tc2 = (TestClass)cc2.newInstance("李四",18);
tc2.showPublic();
}
@Test
//通过类的类对象.newInstance()创建一个对应的无参对象
public void test1() throws Exception{
Class clazz1 = Class.forName("com.dou.reflect.TestClass");
Object obj = clazz1.newInstance();
TestClass tc = (TestClass)obj;
tc.showPublic();
}
@Test
public void test0() throws Exception{
//活动Class对象的三种方法
//getClassLoader()只能获取工程编译后的classes文件夹下的所有资源,而对应的工程路径就是src下的路径
//所有放配置文件放在src下,通过类加载器来获取当前工程下的资源,是最常用的方法
//Class.forName(类的全包名)
Class clazz1 = Class.forName("com.dou.reflect.ReflectDemo1");
ClassLoader classLoader = clazz1.getClassLoader();
URL resource = classLoader.getResource("prop.properties");
String path = resource.getPath();
System.out.println(path);
//2.类.class()
Class clazz2 = ReflectDemo1.class;
ClassLoader cl = clazz2.getClassLoader();
InputStream in = cl.getResourceAsStream("prop.properties");
Properties prop = new Properties();
prop.load(in);
System.out.println("prop.properties加载完成");
Setkeys = prop.keySet();
for (Object object : keys) {
String value = prop.getProperty((String)object);
System.out.println(object+"="+value);
}
//3.对象.getClass()
TestClass ts = new TestClass();
ts.showPublic();
Class clazz3 = ts.getClass();
ClassLoader csl = clazz3.getClassLoader();
URL url = csl.getResource("prop.properties");
String path2 = url.getPath();
System.out.println("prop.properties的全路径:"+path2);
}
@Test
public void test() throws Exception{
//获取src、classes路径下的资源全路径,并加载到文件流中
//传统两步
String path = ReflectDemo1.class.getClassLoader().getResource("prop.properties").getPath();
InputStream is = new FileInputStream(path);
System.out.println("prop.properties文件完成加载1");
//一步走
InputStream ins = ReflectDemo1.class.getClassLoader().getResourceAsStream("prop.properties");
System.out.println("prop.properties文件完成加载2");
}
}
所谓反射,就是给你一个XX.class文件,你通过反射方法,能够拿到该XX类相关的所有资源,比如该类所在位置,通过该类创建一个对象x,获取这个类X创建的对象x的所有公有、私有属性和公有、私有方法。这个技术你值得学习。
首先,我写了一个TestClass.java文件,作为编译成class后要使用的TestClass.class文件,然后ReflectDemo.java演示所有反射技术的demo,这里你将学会反射里常见的方法。先给大家一个方法总结,然后看代码,熟悉相关应用。
1、方法总结:
1.1获取class的三种方法:
第一种:Class clazz = Class.forName(XX.class的全包名)
第二种:Class clazz = XX xx = new XX();xx.getClass();
第三种:Class clazz = XX.class;
见实例代码test0()
1.2如何通过类class文件,拿到该文件里面的资源?这种方式获取的路径方法,永远是固定的,不会随着工程的路径改变而改变,始终都能获取到。
比如,TestClass.class文件(被编译后)所在的classes文件夹下,有prop.properties属性文件,如何拿到这个文件的绝对路径?如何把该文件加载到流中?通过在clazz中有个getClassLoader()方法,得到类加载器ClassLoader,然后再通过getSource()的方法,得到URL,然后再getPath()得到路径名
两种固定写法:
第一种:
![将选中内容分享到新浪微博](https://i-blog.csdnimg.cn/blog_migrate/0b6a0e89b2151920c781ad6ff944a697.gif)
Class clazz = TestClass.class;
ClassLoader classLoader = clazz.getClassLoader();
URL url = classLoader.getResource("prop.properties");
String path = url.getPath();
InputStream ins = new FileInputStream(path);
链式写法为:String path = TestClass.class.getClassLoader().getResource("prop.properties").getPath();
InputStream ins = new FileInputStream(path);
第二种[直接将资源加载成流]:InputStream ins = TestClass.class.getClassLoader().getSourceAsStream("prop.properties");
见实例代码test()
1.3如何用该class文件,创建一个对象?
创建对象有两种方法,直接用xx.newInstance()或使用xx.constructor()获取构造器然后再newInstance()。
第一种:
Class xx = TestClass.class;
Object obj = xx.newInstance();//无参构造方法
TestClass tc = (TestClass)obj;//转换为该类的对象
第二种:
Class xx = TestClass.class;
Constructor cst = xx.getConstructor();//无参构造方法
Object obj = cst.newInstance();//这个也不能有参数
TestClass tc = (TestClass)obj;//转换为该类的对象
见实例代码test1()、test2()
注意:这两种方法,只能使用无参的构造方法来创建无参默认的对象,如果想创建带参的对象呢?
使用构造器,然后指定参数类型,再创建实例对象时,将实参数传递
Class xx = TestClass.class;
Constructor cst = xx.getConstructor(String.class,int.class);//指定参数类型的带参构造方法
Object obj = cst.newInstance("李四",18);//顺便指定好实参
TestClass tc = (TestClass)obj;//转换为该类的对象
见实例代码test2()
1.4如何获取到该类创建的对象中的公有及私有属性值呢?需要用到xx.getField().get()或xx.getDeclaredField().setAccessible().get();
注意:获得公有私有的属性和方法时,必须指定获取哪个对象的,必须创建好一个对象。
Class xx = TestClass.class;
Constructor cst = xx.getConstructor(String.class,int.class);//指定参数类型的带参构造方法
Object obj = cst.newInstance("李四",18);//顺便指定好实参
TestClass tc = (TestClass)obj;//转换为该类的对象
//获取公有属性name:
Field fieldName = xx.getField("name");//指定哪个字段
Object name = fieldName.get(tc);//获取tc对象的name值
String strname = (String)name;
//获取私有属性age:
Field fieldAge = xx.getDeclaredField("age");//获取所有声明的一个叫age的字段
fieldAge.setAccessible(true);//使得该私有age可以被获取
Object age = fieldAge.get(tc)//获取tc的私有age
int intage = (int)age;
见实例代码test3()
1.5如何获取到该类创建的对象中的公有及私有的方法呢?xx.getMethod().invoke()或者xx.getDeclaredMethod().setAccessible().invoke();
注意:获得公有私有的属性和方法时,必须指定获取哪个对象的,必须创建好一个对象。
Class xx = TestClass.class;
Constructor cst = xx.getConstructor();//无参构造方法
Object obj = cst.newInstance();//这个也不能有参数
TestClass tc = (TestClass)obj;//转换为该类的对象
//获得公有的无参的方法:
Method mt1 = xx.getMethod("showPublic");//指定获取哪个方法(showPublic()方法)
mt1.invoke(tc);//获取对象tc中的showPublic()方法
//获得公有的带参的方法:
Method mt2 = xx.getMethod("showPublicParams", String.class,int.class);//指定获取哪个方法,并指定带哪种参数(showPublicParams(String,int)方法)
mt2.invoke(tc1, "刘二麻子",23);//获取对象tc中的showPublicParams并指定传进两个实参
//获得私有的无参方法【两步:1.获得声明的方法;2.让该方法可视化】
Method mt3 = xx.getDeclaredMethod("showPrivate");//获取哪个私有方法(showPrivate()方法)
mt3.setAccessible(true);//该方法可被获取,即可视化
mt3.invoke(tc);//获取对象tc中的showPrivate()方法
见实例代码test4()
1.6如果一个方法中的参数带了泛型,怎么获取该参数以及泛型参数的类型?如参数为(List,int)
见实例代码test5()。其中,getGenericParameterTypes
见实例代码test5()
2、实例代码:
TestClass.java的代码【有公有私有属性,有公有私有方法,有带返回值的方法,有带泛型的方法】如下:
package com.dou.reflect;
import java.util.List;
public class TestClass {
}
//--------------
ReflectDemo.java的代码【常用反射方法】如下:
package com.dou.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import org.junit.Test;
public class ReflectDemo2 {
}