一、反射
1、定义
在Java的反射机制指的是在运行状态下对于任意一个类都能获取到它的属性和方法,对于任何任意一个对象能调用它的所有属性和方法。对于拿到的信息也可以进行修改,这种动态获取信息以及动态调用对象方法的功能就是反射机制。
2、用途
- 在开发过程中,如果一个类的构造方法或对象的属性和方法是私有的,那么就可以利用反射来动态获取信息及修改信息。
反射在开发一些通用的框架时有很大的用途,比如在spring中,我们将所有的类Bean交给spring容器管理,无论是XML配置Bean还是注解配置,当我们从容器中获取Bean来依赖注入时,容器会读取配置,
- 而配置中给的就是类的信息,spring根据这些信息,需要创建那些Bean,spring就动态的创建这些类。
3、反射常用的类
类名 | 用途 |
Class类 | 表示类的实体,就是Java程序中的类和接口 |
Field类 | 表示类的属性 |
Method类 | 表示类的方法 |
Constructor类 | 表示类的构造方法 |
4、获取类对象的三种方式
- Class.forName("类的全路径名")。
- 类名.class方法。
- 对象.getClass()方法。
这三种方式得到的类对象地址是相同的,类对象在内存中只存有一份。
5、反射使用实例
创建了一个Student类,利用反射来获取Student类的相关信息。
public class Student { private int sno; private String name; private Student(int sno, String name) { this.sno = sno; this.name = name; } public Student() { } public int getSno() { return sno; } public void setSno(int sno) { this.sno = sno; } private String getName() { return name; } public void setName(String name) { this.name = name; } }
a、利用反射创建对象
首先获取到类对象,然后调用类对象的newInstance()方法获取到指定类的实例对象,该方法是Object类,然后向下转型为Student类的实例对象。
public static Object getReflectObject(){ try { Class<?> aClass = Class.forName("reflect.Student"); Student student = (Student)aClass.newInstance();//创建类的实例 System.out.println("学生类的实例对象" + student); return student; } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return null; }
b、利用反射获取到私有的构造方法
首先获取到类对象,然后调用其getDeclearedConstructor(int.class,String.class)获取到与传入参数匹配的构造方法,然后利用setAccessible(true)设置权限为公有,可以利用获取到的构造方法通过传入参数来创建对象。
public static void getPriConstructor(){ try { Class<?> sClass = Class.forName("reflect.Student"); Constructor<?> dl = sClass.getDeclaredConstructor(int.class, String.class); dl.setAccessible(true); Student student=(Student)dl.newInstance(12,"王家和"); System.out.println("构造对象"+student); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } }
c、利用反射获取到私有方法
先获取到类对象,然后调用getDeclearedMethod("方法名",方法参数.class)获取到指定方法,然后利用setAccessible(true)设置权限为公有,再创建Student对象,使用方法的invoke(对象,方法参数)来执行方法。
public static void getPriMethod(){ try { Class<?> sClass = Class.forName("reflect.Student"); Method method = sClass.getDeclaredMethod("getName"); method.setAccessible(true); System.out.println("私有方法"+method.getName()); Student stu = (Student)sClass.newInstance(); method.invoke(stu); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } }
d、利用反射获取到私有属性
先获取到类对象,然后调用getDeclearedField("属性名")获取到指定属性,然后利用setAccessible(true)设置权限为公有,再创建Student对象,使用属性的set(对象,修改新值)来修改属性,还可以利用get方法得到属性值。
public static void getPriField(){ try { Class<?> sClass = Class.forName("reflect.Student"); Field field=sClass.getDeclaredField("name"); field.setAccessible(true); Student stu = (Student)sClass.newInstance(); field.set(stu,"高山"); String str=(String)field.get(stu); System.out.println("私有属性:"+str); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } }
6、反射的优缺点
优点:
- 可以获取到任何类的相关信息,并能调用类的属性和方法。
- 增加程序的灵活性和扩展性,降低了耦合度,提高了自适应能力。
- 反射运用于许多框架。
缺点:
- 效率低。
- 代码更加复杂。
- 破坏了封装性。
二、枚举
1、定义
将一组常量组织起来创建出个类。
2、举例
例如利用枚举可以定义一个天气类,假设有晴天、雨天、雷电和多云天气。
public enum Weather { SUN,THUNDER,CLOUDY,RAINY; }
枚举也可以定义构造方法,枚举中所有的构造方法都是私有的,由于任何枚举类都继承了Enum类,所以在创建带参的构造方法时,类中所有的对象都必须带参,否则就定义一个无参的构造方法。
3、常见方法
定义任何枚举类都会默认继承Enum类,并继承Enum类的相关方法。
方法名称 | 描述 |
values() | 以数组形式返回枚举类型的所有成员 |
ordinal() | 获取枚举成员的索引位置 |
valueOf() | 讲普通字符串装换为枚举实例 |
comPareTo() | 比较两个枚举成员在定义的顺序 |
注意:在使用valueOf()方法时,传入的参数并不是随便的字符串,而是枚举类中有的。
4、枚举的优缺点
优点:
- 简单、安全。
- 枚举具有内置方法,代码更加优雅。
缺点:
- 不可继承,无法拓展。
5、利用枚举实现安全的单例模式
利用反射机制是无法获取到枚举类的信息,所以使用枚举实现单例模式更加安全。
public enum TestEnum { INSTANCE; public TestEnum getInstance(){ return INSTANCE; } }