day24复习
1. 反射的理解
lReflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
- 体会反射的动态性
//体现了反射的动态性
//获取指定的类的对象
public Object method(String className) throws Exception{
Class clazz = Class.forName(className);
Object instance = clazz.newInstance();
return instance;
}
//调用指定类的指定的方法
public Object method(String className,String methodName){
Class clazz = Class.forName(className);
Object instance = clazz.newInstance();
Method method = clazz.getDeclaredMethod(methodName);
method.setAccessable(true);
return method.invoke(instance);
}
- 体会反射都可以做什么?
public class ReflectionTest {
//不使用反射
@Test
public void test1(){
//1. 创建Person类的对象
Person p1 = new Person();
//2. 通过对象,调用实例变量
p1.age = 12;
System.out.println(p1.age);
//3. 通过对象,调用方法
p1.show();
}
//使用反射,做上面同样的事
@Test
public void test2() throws IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
//1. 创建Person类的对象
Class clazz = Person.class;
// Object instance = clazz.newInstance();
Person p1 = (Person) clazz.newInstance();
//2. 通过对象,调用实例变量
Field ageField = clazz.getField("age");
ageField.set(p1,12);
System.out.println(ageField.get(p1));
//3. 通过对象,调用方法
Method showMethod = clazz.getMethod("show");
showMethod.invoke(p1);
}
//体现了反射的动态性
public Object method(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class clazz = Class.forName(className);
Object instance = clazz.newInstance();
return instance;
}
//通过反射,可以调用Person类中的私有结构
@Test
public void test3() throws Exception {
Class clazz = Class.forName("com.atguigu.java.Person");
//1. 调用私有的构造器:private Person(String name,int age)
Constructor con = clazz.getDeclaredConstructor(String.class, int.class);
con.setAccessible(true);
Person p1 = (Person) con.newInstance("Tom",12);
System.out.println(p1);
//2. 调用私有的属性:private String name;
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(p1,"Jerry");
System.out.println(nameField.get(p1));
//3. 调用私有的方法:private String showNation(String nation)
Method showNationMethod = clazz.getDeclaredMethod("showNation", String.class);
showNationMethod.setAccessible(true);
String info = (String) showNationMethod.invoke(p1,"中国");
System.out.println(info);
}
/*
* 问题1:通过反射,也可以创建类的对象、调用方法等操作,那么跟以前的方式比,如何选择?
* 使用频率上说:以前的方式更多,反射的方式很少。
* 使用场景上说:大部分的场景中,创建的对象和要调用的方法都是确定的,所有都使用以前的方式。
* 如果出现了不确定的对象的创建或方法的调用,此时才会考虑用反射。
*
* 问题2:反射打破了类的封装的特性?如何看待? 单例模式可能也不保?如何看待?
* 不矛盾!
* 类的封装性:建议我们是否要调用
* 反射:体现我们是否能调用
*
* */
}
2. Class的理解
/**
*
* 1. 理解Class类
* 2. 获取Class的实例
* 3. 了解类的加载与类的加载器
*
*
* Class看做是反射的源头。
* java程序经过javac.exe编译之后,会生成一个或多个.class结尾的字节码文件。接着,我们使用java.exe 指令
* 将指定.class文件对应的类加载到内存中。此类就称为运行时类。此运行时类本身就作为Class的一个实例。
* 补充:此运行时类加载到方法区的缓存位置;运行时类的加载使用的是类的加载器。
*
* 换句话说:Class的一个实例就会对应一个加载到内存中的运行时类。(狭义)
*
* 说明:通常加载到方法区的运行时类只有一份,不会重复加载。
*
* @author shkstart
* @create 10:28
*/
/*
Class的实例都可以指向哪些结构呢?
(1)class:
外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
(2)interface:接口
(3)[]:数组
(4)enum:枚举
(5)annotation:注解@interface
(6)primitive type:基本数据类型
(7)void
* */
@Test
public void test2(){
Class c1 = Object.class;
Class c2 = Comparable.class;
Class c3 = String[].class;
Class c4 = int[][].class;
Class c5 = ElementType.class;
Class c6 = Override.class;
Class c7 = int.class;
Class c8 = void.class;
Class c9 = Class.class;
int[] a = new int[10];
int[] b = new int[100];
System.out.println(a);
Class c10 = a.getClass();
Class c11 = b.getClass();
//对于数组来说:只要元素类型与维度一样,就是同一个Class
System.out.println(c10 == c11);
}
3. 获取Class的实例
//获取Class的实例(讲4种方式,需要大家掌握前3种方式)
@Test
public void test1() throws ClassNotFoundException {
//方式1:调用运行时类的class属性
Class<Person> clazz = Person.class;
Class<String> clazz1 = String.class;
//方式2:调用Class的静态方法:forName(String className)
Class clazz2 = Class.forName("com.atguigu.java.Person");
//方式3:调用对象的getClass()
Person p = new Person();
Class clazz3 = p.getClass();
System.out.println(clazz == clazz2 && clazz == clazz3);
//方式4:使用类的加载器
Class clazz4 = ClassLoader.getSystemClassLoader().loadClass("com.atguigu.java.Person");
System.out.println(clazz == clazz4);
}
4. 了解类的加载过程及类的加载器
4.1 类的加载过程
4.2 了解类的加载器
/*
测试类的加载器
*/
@Test
public void test3() throws ClassNotFoundException {
//自定义类使用的是系统类加载器进行的加载
Class clazz1 = Class.forName("com.atguigu.java.Person");
System.out.println(clazz1.getClassLoader());
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
//java核心api使用的是引导类加载器。
//引导类加载器不可以直接获取。
Class clazz2 = String.class;
System.out.println(clazz2.getClassLoader());
}
@Test
public void test4(){
//获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
//获取扩展类加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);
//获取引导类加载器:获取失败
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);
}
- 如下的代码需要掌握
//需要掌握如下的代码
@Test
public void test5() throws IOException {
Properties pros = new Properties();
//方式1:此时默认的相对路径是当前的module
// FileInputStream is = new FileInputStream("info.properties");
FileInputStream is = new FileInputStream("src//info1.properties");
//方式2:使用类的加载器
//此时默认的相对路径是当前module的src目录
// InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("info1.properties");
pros.load(is);
//获取配置文件中的信息
String name = pros.getProperty("name");
String password = pros.getProperty("password");
System.out.println("name = " + name + ", password = " + password);
}
上述代码对应的配置文件内容及位置:
【info.properites】
name=Tom
password=abc123
【info1.properites】
name=Jerry
password=abc123
5. 反射的应用一:创建对应的运行时类的对象
- 反射的应用一、二、三使用的大前提:
/**
* @author shkstart
* @create 14:07
*/
public class Creature<T> {
boolean gender;
public int id;
public void breath(){
System.out.println("呼吸");
}
private void info(){
System.out.println("我是一个生物");
}
}
package com.atguigu.java1;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
/**
* @author shkstart
* @create 14:09
*/
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "abc";
}
package com.atguigu.java1;
/**
* @author shkstart
* @create 14:09
*/
public interface MyInterface {
void method();
}
package com.atguigu.java1;
import java.util.ArrayList;
/**
* @author shkstart
* @create 9:35
*/
@MyAnnotation(value="hello")
public class Person extends Creature<String> implements Comparable<Person>,MyInterface{
private String name;
@MyAnnotation
public int age;
private static String info;
public Person(){
// System.out.println("Person()...");
}
protected Person(int age){
this.age = age;
}
private Person(String name, int age){
this.name = name;
this.age = age;
}
@MyAnnotation
public void show() throws RuntimeException,ClassNotFoundException{
System.out.println("你好,我是一个Person");
}
private String showNation(String nation,int age){
System.out.println("showNation...");
return "我的国籍是:" + nation + ",生活了" + age + "年";
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Person o) {
return 0;
}
@Override
public void method() {
}
public static void showInfo(){
System.out.println("我是一个人");
}
}
/*
* 测试反射的应用一:创建对应的运行时类的对象。
*
* @author shkstart
* @create 11:31
*/
public class InstanceTest {
@Test
public void test1() throws IllegalAccessException, InstantiationException {
//获取Class的实例,对应着一个运行时类
Class clazz = Person.class;
//如何创建Person类的对象
/*
* 要想保证newInstance()可以正常执行,必须:
* ① 运行时类中必须提供空参的构造器
* ② 空参的构造器的访问权限要够。不一定非得是public
* */
Person obj = (Person) clazz.newInstance();
System.out.println(obj);
}
}
6. 反射的应用二:获取运行时类的完整的类结构
- 了解
package com.atguigu.java2;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import org.junit.Test;
import com.atguigu.java1.Person;
public class FieldTest {
@Test
public void test1(){
Class clazz = Person.class;
//getFields():获取到运行时类本身及其所有的父类中声明为public权限的属性
// Field[] fields = clazz.getFields();
//
// for(Field f : fields){
// System.out.println(f);
// }
//getDeclaredFields():获取当前运行时类中声明的所有属性
Field[] declaredFields = clazz.getDeclaredFields();
for(Field f : declaredFields){
System.out.println(f);
}
}
//权限修饰符 变量类型 变量名
@Test
public void test2(){
Class clazz = Person.class;
Field[] declaredFields = clazz.getDeclaredFields();
for(Field f : declaredFields){
//1.权限修饰符
int modifier = f.getModifiers();
System.out.print(Modifier.toString(modifier) + "\t");
// //2.数据类型
Class type = f.getType();
System.out.print(type.getName() + "\t");
//
// //3.变量名
String fName = f.getName();
System.out.print(fName);
//
System.out.println();
}
}
}
- 了解
package com.atguigu.java2;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.junit.Test;
import com.atguigu.java1.Person;
public class MethodTest {
@Test
public void test1() {
Class clazz = Person.class;
// getMethods():获取到运行时类本身及其所有的父类中声明为public权限的方法
// Method[] methods = clazz.getMethods();
//
// for(Method m : methods){
// System.out.println(m);
// }
// getDeclaredMethods():获取当前运行时类中声明的所有方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m : declaredMethods) {
System.out.println(m);
}
}
// 注解信息
// 权限修饰符 返回值类型 方法名(形参类型1 参数1,形参类型2 参数2,...) throws 异常类型1,...{}
@Test
public void test2() {
Class clazz = Person.class;
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m : declaredMethods) {
// 1.获取方法声明的注解
Annotation[] annos = m.getAnnotations();
for (Annotation a : annos) {
System.out.println(a);
}
// 2.权限修饰符
System.out.print(Modifier.toString(m.getModifiers()) + "\t");
// 3.返回值类型
System.out.print(m.getReturnType().getName() + "\t");
// 4.方法名
System.out.print(m.getName());
System.out.print("(");
// 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.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();
}
}
}
- 了解
package com.atguigu.java2;
import com.atguigu.java1.Person;
import org.junit.Test;
import java.lang.reflect.Constructor;
/**
* @author shkstart
* @create 14:31
*/
public class ConstructorTest {
@Test
public void test1(){
Class clazz = Person.class;
//getConstructors():获取当前运行时类中声明为public权限的构造器
// Constructor[] cons1 = clazz.getConstructors();
// for(Constructor c : cons1){
// System.out.println(c);
// }
//getDeclaredConstructors():获取当前运行时类中所有的构造器
Constructor[] cons2 = clazz.getDeclaredConstructors();
for(Constructor c : cons2){
System.out.println(c);
}
}
}
- 掌握
package com.atguigu.java2;
import com.atguigu.java1.Person;
import org.junit.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* @author shkstart
* @create 14:35
*/
public class OtherTest {
//获取运行时类的父类
@Test
public void test1(){
Class clazz = Person.class;
Class superclass = clazz.getSuperclass();
System.out.println(superclass);
}
//获取带泛型的父类
@Test
public void test2(){
Class clazz = Person.class;
Type genericSuperclass = clazz.getGenericSuperclass();
System.out.println(genericSuperclass);
}
//获取父类的泛型
@Test
public void test3(){
Class clazz = Person.class;
Type genericSuperclass = clazz.getGenericSuperclass();
ParameterizedType type = (ParameterizedType) genericSuperclass;
Type[] actualTypeArguments = type.getActualTypeArguments();//获取泛型的参数
System.out.println(((Class)actualTypeArguments[0]).getName());
}
//获取实现的接口
@Test
public void test4(){
Class clazz = Person.class;
Class[] interfaces = clazz.getInterfaces();
for(Class i : interfaces){
System.out.println(i);
}
}
//获取所在的包
@Test
public void test5(){
Class clazz = Person.class;
Package package1 = clazz.getPackage();
System.out.println(package1.getName());
}
//获取注解
@Test
public void test6(){
Class clazz = Person.class;
Annotation[] annotations = clazz.getAnnotations();
for(Annotation a : annotations){
System.out.println(a);
}
}
}
7. 反射的应用三:调用运行时类的指定结构
- 重点掌握
package com.atguigu.java2;
import com.atguigu.java1.Person;
import junit.extensions.TestSetup;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 反射的应用三:调用对应的运行时类的指定的结构:属性、方法、构造器
*
* @author shkstart
* @create 15:05
*/
public class ReflectionTest {
//调用指定的属性
@Test
public void test1() throws NoSuchFieldException, IllegalAccessException, InstantiationException {
Class clazz = Person.class;
//创建运行时类的对象
Person p = (Person) clazz.newInstance();
//public int age;
//getField(String fieldName):可以获取当前运行时类中声明为public权限的属性。
// Field ageField = clazz.getField("age");
// //设置一个值
// ageField.set(p,10);
// //获取此值
// System.out.println(ageField.get(p));
//private String name;
//使用反射获取指定属性并调用的通用的操作步骤:
//第1步:getDeclaredField(String fieldName):获取当前运行时类中声明为指定名称的属性
Field nameField = clazz.getDeclaredField("name");
//第2步:设置此属性是可访问的
nameField.setAccessible(true);
//第3步:针对于属性的设置和调用的过程
//设置一个值
nameField.set(p,"Tom");
//获取此值
System.out.println(nameField.get(p));
}
//调用方法
@Test
public void test2() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class clazz = Person.class;
//创建运行时类的对象
Person p = (Person) clazz.newInstance();
//使用反射调用指定的方法
//private String showNation(String nation,int age)
//1. getDeclaredMethod(String methodName,Class ... paramTypes):获取运行时类中的指定的方法
Method showNationMethod = clazz.getDeclaredMethod("showNation", String.class, int.class);
//2.设置此方法是可访问的
showNationMethod.setAccessible(true);
//3.调用此方法
//invoke()方法的返回值即为要调用的方法的返回值。
String returnValue= (String) showNationMethod.invoke(p,"CHN",20);
System.out.println(returnValue);
}
//调用当前运行时类中静态的结构:属性、方法
@Test
public void test3() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class clazz = Person.class;
//调用指定的属性:
//private static String info;
//1.
Field infoField = clazz.getDeclaredField("info");
//2.
infoField.setAccessible(true);
//3.1
// infoField.set(Person.class,"人");
infoField.set(null,"人");
//3.2
// System.out.println(infoField.get(Person.class));
System.out.println(infoField.get(null));
//调用指定的方法
//public static void showInfo()
Method showInfoMethod = clazz.getDeclaredMethod("showInfo");
showInfoMethod.setAccessible(true);
Object returnValue = showInfoMethod.invoke(null);
System.out.println(returnValue);
}
//调用指定的构造器
@Test
public void test4() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class clazz = Person.class;
//private Person(String name, int age)
//1. getDeclaredConstructor(Class ... args):获取指定参数的构造器
Constructor con = clazz.getDeclaredConstructor(String.class, int.class);
//2. 保证此构造器是可访问的
con.setAccessible(true);
//3. 调用此构造器,创建运行时类的对象
Person p = (Person) con.newInstance("Tom",12);
System.out.println(p);
//使用如下的操作,替换原有的Class调用newInstance():
//public Person()
Constructor con1 = clazz.getDeclaredConstructor();
con1.setAccessible(true);
Person p1 = (Person) con1.newInstance();
System.out.println(p1);
}
}
的构造器
@Test
public void test4() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class clazz = Person.class;
//private Person(String name, int age)
//1. getDeclaredConstructor(Class ... args):获取指定参数的构造器
Constructor con = clazz.getDeclaredConstructor(String.class, int.class);
//2. 保证此构造器是可访问的
con.setAccessible(true);
//3. 调用此构造器,创建运行时类的对象
Person p = (Person) con.newInstance("Tom",12);
System.out.println(p);
//使用如下的操作,替换原有的Class调用newInstance():
//public Person()
Constructor con1 = clazz.getDeclaredConstructor();
con1.setAccessible(true);
Person p1 = (Person) con1.newInstance();
System.out.println(p1);
}
}