目录
4、获取方法的其他结构@Xxxx权限修饰符 返回值类型 方法名(参数类型1 形参名1,...)throws XxxException{}
一、了解类加载器
public class ClassLoaderTest {
@Test
public void test1(){
// 对于自定义类,使用系统类加载器进行加载
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
System.out.println(classLoader);
// 调用系统类加载器的getParent(),获取扩展类加载器
ClassLoader classLoaderParent = classLoader.getParent();
System.out.println(classLoaderParent);
// 调用扩展类加载器的getParent(),无法获取引导类加载器
ClassLoader parent = classLoaderParent.getParent();
System.out.println(parent);
ClassLoader classLoader1 = String.class.getClassLoader();
System.out.println(classLoader1);
}
二、读取配置文件时有两种方法:
properties():用来读取配置文件的一个方法
public void test2() throws Exception {
Properties properties = new Properties();
// 读取配置文件的方式一:
// FileInputStream fis = new FileInputStream("jdbc.properties"); //此时文件默认在当前module下
// properties.load(fis);
// 读取配置文件的方式二:使用ClassLoader
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
InputStream resourceAsStream = classLoader.getResourceAsStream("jdbc1.properties");//此时文件默认在本module下的src中
properties.load(resourceAsStream);
String user = properties.getProperty("user");
String password = properties.getProperty("password");
System.out.println("user = "+user + ",password = "+ password);
}
三、关于java.lang.Class类的理解
Class类的实例对应着加载到内存中的一个运行时类。 1.类的加载过程: 程序经过javac.exe命令以后,会生成一个或多个字节码文件(.cLass结尾)。 接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。 此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例。 2.换句话说,Class的实例就对应着一个运行时类。 3.加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式来获取此运行时类。 四、那些类型可以有Class对象? (1) class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类 (2) interface:接口 (3)[]:数组 (4) enum:枚举 (5) annotation:注解@interface (6) primitive type:基本数据类型 (7) void
五、获取运行时类(获取Class实例)
public void test3() throws ClassNotFoundException {
// 方式一:调用运行时类的属性:.class
Class<Person> personClass = Person.class;
System.out.println(personClass); //class com.haiyu.java.Person
// 方式二:通过运行时类的对象,调用getClass()
Person person = new Person();
Class aClass2 = person.getClass();
System.out.println(aClass2);
// 方式三:调用Class的静态方法:.forName(String classpath)
Class aClass = Class.forName("com.haiyu.java.Person");
System.out.println(aClass);
// 方式四:使用类的加载器:ClassLoader (了解)
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
Class<?> aClass1 = classLoader.loadClass("com.haiyu.java.Person");
System.out.println(aClass1);
}
六、创建运行时类的对象
newInstance():调用此方法,创建对应的运行时类的对象 要想此方法正常的创建运行时类的对象,要求: 1.运行时类必须提供空参的构造器 2.空参的构造器的访问权限得够。通常就是public的 在javabean中要求提供一个public的空参构造器,原因: 1.便于通过反射创建运行时类的对象, 2.便于子类继承此运行时类时,默认调用super(),保证父类有此构造器
Class<Person> personClass = Person.class;//获取运行时类
Person person = personClass.newInstance();//调用运行时类的newInstance()创建对象,调的是空参构造器
七、对运行时类的对象进行操作
1、获取属性结构:
public void test1(){
Class clazz = Person.class;
// getFields():获取当前运行时类及其所有父类中声明为public的属性
Field[] field = clazz.getFields();
for (Field f : field){
System.out.println(f);
}
System.out.println("*********************");
// getDeclaredFields():获取当前运行时类声明的所有属性(不包括父类中声明的属性)
Field[] declaredFields = clazz.getDeclaredFields();
for (Field f : declaredFields){
System.out.println(f);
}
}
2、获取属性的权限修饰符 数据类型 变量名
public void test2(){
Class<Person> clazz = Person.class;
Field[] declaredFields = clazz.getDeclaredFields();
for (Field f : declaredFields){
// 获取属性的权限修饰符
int modi = f.getModifiers();
System.out.print(Modifier.toString(modi)+ "\t");
// 获取属性的数据类型
Class<?> type = f.getType();
System.out.print(type.getName() + "\t");
// 获取属性的变量名
String name = f.getName();
System.out.print(name);
System.out.println();
}
}
3、获取方法结构:
public void test1() {
Class clazz = Person.class;
// getMethods():获取当前运行时类及其所有父类中声明为public的方法
Method[] methods = clazz.getMethods();
for (Method m : methods) {
System.out.println(m);
}
System.out.println("*******************************");
// getDeclaredMethods():获取当前运行时类声明的所有方法(不包括父类中声明的属性)
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m : declaredMethods) {
System.out.println(m);
}
}
4、获取方法的其他结构
@Xxxx
权限修饰符 返回值类型 方法名(参数类型1 形参名1,...)throws XxxException{}
public void test2() {
Class clazz = Person.class;
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m : declaredMethods) {
// 1.获取方法声明的注解
Annotation[] annotations = m.getAnnotations();
for (Annotation a : annotations) {
System.out.println(a);
}
// 2.获取权限修饰符
int modifiers = m.getModifiers();
System.out.print(Modifier.toString(modifiers) + "\t");
// 3.返回值类型
System.out.print(m.getReturnType().getName() + "\t");
// 4.方法名
System.out.print(m.getName() + "(");
// 5.形参列表
Class<?>[] parameterTypes = m.getParameterTypes();
if (!(parameterTypes == null || parameterTypes.length == 0)) {
for (int i = 0; i < parameterTypes.length; i++) {
if (i == parameterTypes.length - 1) {
System.out.print(parameterTypes[i].getName() + " args_" + i);
break;
}
System.out.print(parameterTypes[i].getName() + " args_" + i + ",");
}
}
System.out.print(")");
// 6.抛出的异常
Class<?>[] exceptionTypes = m.getExceptionTypes();
if (!(exceptionTypes == null || exceptionTypes.length == 0)) {
System.out.print(" throws ");
for (int i = 0; i < exceptionTypes.length; i++) {
if (i == exceptionTypes.length - 1) {
System.out.print(exceptionTypes[i].getName());
break;
}
System.out.print(exceptionTypes[i].getName() + ",");
}
}
System.out.println();
}
}
5、获取构造器
public void test1() {
Class clazz = Person.class;
// getConstructors():获取当前运行时类中声明为public的构造器
Constructor[] constructors = clazz.getConstructors();
for (Constructor c : constructors) {
System.out.println(c);
}
System.out.println();
// getDeclaredConstructors():获取当前运行时类中声明的所有构造器
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor d : declaredConstructors) {
System.out.println(d);
}
}
6、取运行时类的父类
@Test
public void test2() {
Class clazz = Person.class;
Class superclass = clazz.getSuperclass();
System.out.println(superclass);
}
7、获取运行时类的带泛型的父类
public void test3() {
Class clazz = Person.class;
Type genericSuperclass = clazz.getGenericSuperclass();
System.out.println(genericSuperclass);
}
8、获取运行时类的带泛型的父类的泛型
public void test4() {
Class clazz = Person.class;
Type genericSuperclass = clazz.getGenericSuperclass();
// 强转为这个:带参数的类型
ParameterizedType p = (ParameterizedType) genericSuperclass;
// 获取带参数的类型的参数
Type[] actualTypeArguments = p.getActualTypeArguments();
for (Type a : actualTypeArguments){
System.out.println(a.getTypeName());
}
}
9、获取运行时类实现的接口
public void test5(){
Class clazz = Person.class;
Class[] interfaces = clazz.getInterfaces();
for (Class i : interfaces){
System.out.println(i);
}
System.out.println();
//获取运行时类的父类实现的接口
Class[] interfaces1 = clazz.getSuperclass().getInterfaces();
for (Class i : interfaces1){
System.out.println(i);
}
}
10、获取当前运行时类所在的包
public void tset6(){
Class clazz = Person.class;
Package aPackage = clazz.getPackage();
System.out.println(aPackage);
}
11、获取当前运行时类声明的注解
public void tset7(){
Class clazz = Person.class;
Annotation[] annotations = clazz.getAnnotations();
for (Annotation a : annotations){
System.out.println(a);
}
}
12、调用运行时类中指定的结构:属性、方法、构造器(重点)
public class ReflectionTest {
@Test
public void test1() throws Exception {
Class clazz = Person.class;
//创建运行时类的对象
Person person = (Person) clazz.newInstance();
//获取运行时类中指定变量名的属性,一般就用getDeclaredXxx()来获取。不用getXxx()
Field name = clazz.getDeclaredField("name");
//保证当前属性是可以访问的 !!!
name.setAccessible(true);
//设置当前属性的值
name.set(person, "tom");
//获取当前属性的值
int pname = (int) name.get(person);
System.out.println(pname);
}
//如何操作运行时类中指定的方法 ----需要掌握
@Test
public void test2() throws Exception {
Class clazz = Person.class;
//创建运行时类的对象
Person person = (Person) clazz.newInstance();
// 1.获取指定的某个方法
// getDeclaredMethod():参数1 ︰指明获取的方法的名称﹑ 参数2:指明获取的方法的形参列表
Method show = clazz.getDeclaredMethod("show", String.class, int.class);
// 保证方法是可以访问的
show.setAccessible(true);
// 调用方法的invock():参数1:方法的调用者 参数2:给方法形参赋值的实参
// invoke的返回值就是对应类中调用方法的返回值
Object p = show.invoke(person, "haiyu", 12);
System.out.println(p);
System.out.println();
// 如何调用静态方法
Method showDesc = clazz.getDeclaredMethod("showDesc");
showDesc.setAccessible(true);
// 如果调用的运行时类的方法没有返回值,则invoke()返回null
Object invoke = showDesc.invoke(clazz);
System.out.println(invoke);//null
}
// 如何调用运行时类中指定的构造器
@Test
public void test3() throws Exception {
Class<Person> clazz = Person.class;
//获取指定的构造器:getDeclaredConstructor():
Constructor<Person> declaredConstructor = clazz.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
// 调用此构造器创建运行时类的对象
Person person = declaredConstructor.newInstance();
System.out.println(person);
}
}
问题
疑问1:通过直接new的方式或反射的方式都可以调用公共的结构,开发中到底用那个? 建议:直接new的方式。 反射主要是用它的动态性 疑问2:反射机制与面向对象中的封装性是不是矛盾的?如何看待两个技术? 不矛盾。 封装性是建议调用公共的,不建议调用私有的; 而反射机制是看能不能调用,非要调用的话公共的私有的都行。