一、反射的概述:
1、基本概述:
(1)、(Class类)创建clazz对应的运行时类Person类的对象:
Class clazz=Person.class;
解析:clazz:栈空间的引用 ; Person.class:堆空间的一个实体,这样写之后Person类中的所有内容都可以引用。
(2)、(Field类)使用反射机制操作运行时类的指定属性:
①、调用public类型的属性
Field f1=clazz.getField("name");//通过反射的方式获取name属性
f1.set(p,"LiDeHua");//将p对象的name属性改为"LiuDeHua"
System.out.println(p);
②、调用非public类型的属性
Field f2=clazz.getDeclaredField("age");
f2.setAccessible(true);
f2.set(p, 23);
System.out.println(p);
(3)、(Method类)通过反射调用运行时类的指定的方法,方法名后不加小括号
①、用反射调用无参的方法
Method m1=clazz.getMethod("show");
//m1.invoke(p, args)//args用来书写类中方法的形参
m1.invoke(p);//如果没有形参可省略第二位。
②、用反射调用有参的方法
Method m2=clazz.getMethod("nation",String.class);
//对于有参的方法,需要在方法名后加上形参的类型,有几个参数就加几个类型。
m2.invoke(p, "China");
2、Class类:
(1)、反射的概念了解:
反射:原来java程序是通过运行时类来找到类的属性和方法;现在是倒过来的,通过一个类对象来找类进而找类内部的属性、方法。
(2)、 java.lang.Class:是反射的源头。
我们创建了一个类,通过编译(javac.exe),生成对应的.class文件。之后我们使用java.exe加载(JVM的类加载器完成)此.class文件,
此.class文件加载到内存以后,就是一个运行时类,存在在缓存区,那么这个运行时类本身就是一个Class的实例!
1、每一个运行时类只加载一次!
2、有了Class的实例以后我们才可以进行如下的操作:
1*)、创建对应的运行时类的对象
2)、获取对应的运行时类的完整结构(属性、方法、构造器、内部类、父类、所在的包、异常、注解.......)
3*)、调用对应的运行时类的指定的结构(属性、方法、构造器)
4)、反射的应用:动态代理
(3)、如何获取Class的实例(3种)
@Test
public void testReflection() throws ClassNotFoundException{
//1、调用运行时类本身的.class属性 如果没有Person类的话编译时就会报错
Class clazz1=Person.class; //①、自定义的类的.class属性
System.out.println(clazz1.getName());
Class clazz2=String.class; //②、系统类的.class属性
//2、通过运行时类的对象获取。通过此方法,体会一下反射的动态性。
Person p1=new Person();//根据传进来的对象的不同,造的对象不同(用newInstance造的对象)。
Class clazz3=p1.getClass();//创建clazz4的一个实例。
System.out.println(clazz3.getName());
//3、通过Class的静态方法获取 运行时才会报错
String className="com.atguigu.fanshe.Person";
Class clazz4=Class.forName(className);
System.out.println(clazz4.getName());
//4、(了解)通过类的加载器
ClassLoader classLoadar=this.getClass().getClassLoader();
Class clazz5=classLoadar.loadClass(className);
System.out.println(clazz5.getName());
}
总代码:
package com.atguigu.fanshe;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.junit.Test;
public class TestReflection {
//如何获取Class的实例(3种)
@Test
public void testReflection() throws ClassNotFoundException{
//1、调用运行时类本身的.class属性
Class clazz1=Person.class; //①、自定义的类的.class属性
System.out.println(clazz1.getName());
Class clazz2=String.class; //②、系统类的.class属性
System.out.println(clazz2);
//2、通过运行时类的对象获取
Person p1=new Person();
Class clazz3=p1.getClass();
System.out.println(clazz3.getName());
//3、通过Class的静态方法获取。通过此方法,体会一下反射的动态性。
String className="com.atguigu.fanshe.Person";//根据传进来的对象的不同,造的对象不同(用newInstance造的对象)。
Class clazz4=Class.forName(className);
// clazz4.newInstance(); //创建clazz4的一个实例。
System.out.println(clazz4.getName());
//4、(了解)通过类的加载器
ClassLoader classLoadar=this.getClass().getClassLoader();
Class clazz5=classLoadar.loadClass(className);
System.out.println(clazz5.getName());
}
/*
* java.lang.Class:是反射的源头。
* 我们创建了一个类,通过编译(javac.exe),生成对应的.class文件。之后我们使用java.exe加载(JVM的类加载器完成)此.class文件,
* 此.class文件加载到内存以后,就是一个运行时类,存在在缓存区,那么这个运行时类本身就是一个Class的实例!
*
* 1、每一个运行时类只加载一次!
* 2、有了Class的实例以后我们才可以进行如下的操作:
* 1*)、创建对应的运行时类的对象
* 2)、获取对应的运行时类的完整结构(属性、方法、构造器、内部类、父类、所在的包、异常、注解.......)
* 3*)、调用对应的运行时类的指定的结构(属性、方法、构造器)
* 4)、反射的应用:动态代理
* */
@Test
public void testReflection3() {
Person p=new Person();
Class clazz=p.getClass();//通过运行时类的对象,调用其getClass()方法,返回其运行时类。(用这个getClass()方法来知道p来自于哪个类。)
}
//有了反射,可以通过反射创建一个类的对象,并调用其中的结构
@Test
public void testReflection2() throws Exception{
Class clazz1=String.class;//类.class。
Class<Person> clazz=Person.class;//默认是Object类型,如果想改类型需要在Class后加"<类型>"
/* clazz:栈空间的引用 ; Person.class:堆空间的一个实体*/
//1、创建clazz对应的运行时类Person类的对象
Person p=(Person)clazz.newInstance();
System.out.println(p);
//2、通过反射调用运行时类的指定的属性:
//(1)、调用public类型的属性
Field f1=clazz.getField("name");//通过反射的方式获取name属性
f1.set(p,"LiDeHua");//将p对象的name属性改为"LiuDeHua"
System.out.println(p);
//(2)、调用非public类型的属性
Field f2=clazz.getDeclaredField("age");
f2.setAccessible(true);
f2.set(p, 23);
System.out.println(p);
//3、通过反射调用运行时类的指定的方法,方法名后不加小括号。
//(1)、用反射调用无参的方法
Method m1=clazz.getMethod("show");
// m1.invoke(p, args)//args用来书写类中方法的形参
m1.invoke(p);//如果没有形参可省略第二位。
//(2)、用反射调用有参的方法
Method m2=clazz.getMethod("nation",String.class);//对于有参的方法,需要在方法名后加上形参的类型,有几个参数就加几个类型。
m2.invoke(p, "China");//
}
//没有反射的,如何创建一个类的对象,并调用其中的属性方法。
@Test
public void testReflection1() {
Person p=new Person();
p.setAge(23);
p.setName("gg");
p.show();
p.nation("CN");
}
}
总代码结束。
3、类的加载器
//4、(了解)通过类的加载器
ClassLoader classLoadar=this.getClass().getClassLoader();
Class clazz5=classLoadar.loadClass(className);
System.out.println(clazz5.getName());
public class TestReflection {
//关于类的加载器
@Test
public void test5() throws ClassNotFoundException, IOException {
ClassLoader loader1=ClassLoader.getSystemClassLoader();//系统的加载器
System.out.println(loader1);
ClassLoader loader2=loader1.getParent();
System.out.println(loader2);
ClassLoader loader3=loader2.getParent();
System.out.println(loader3);
Class clazz1=Person.class;
ClassLoader loader4=clazz1.getClassLoader();
System.out.println(loader4);
String className="java.lang.String";
Class clazz2=Class.forName(className);
ClassLoader loader5=clazz2.getClassLoader();
System.out.println(loader5);
//掌握如下:
//*****方法一、在具体的包里用下面的
// ClassLoader loader=this.getClass().getClassLoader();
// InputStream is=loader.getResourceAsStream("com\\atguigu\\java\\jdbc.properties");
// Properties pros=new Properties();
// pros.load(is);
// String name=pros.getProperty("user");
// System.out.println(name);
//
// String password=pros.getProperty("password");
// System.out.println(password);
//******方法二、在一个目录下用下面的
FileInputStream is=new FileInputStream(new File("jdbc1.properties"));
Properties pros=new Properties();
pros.load(is);
String name=pros.getProperty("user");
System.out.println(name);
String password=pros.getProperty("password");
System.out.println(password);
}
}