一.反射
1.使用情景
当你做程序开发时,你会发现定义接口,可以提高程序扩展性,扩展功能类实现接口即可。可是你会发现源码中只有引用型变量不用修改了而已,扩展功能时不能避免的就是建立功能类的对象,对象是必须要建立的。这时就有了反射技术出现解决了这一问题,只要你把功能类类名定义在一个指定配置文件中,你不用修改任何源程序代码的情况下完成功能的扩展。反射的出现大大提高了程序的扩展性
2.解释
反射就是加载类,并解刨出类的各个组成部分
3.描述
3.1 Class类的含义
(1)Class类是对*.class文件共性内容向上抽取后得到的类,是一个描述类的类。就像多个对象都是同一个类构造的一样。
(2)字段(成员变量)、构造函数、成员函数都封装为了对象存储在Class类中,来对字节码文件进行统一的描述
(3)重点:每一个Class对象都单单指一个*.class文件
3.2 使用方法
方法摘要 |
---|
Field |
getField(String name) 返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。(通过变量名来定位哪一个变量)
|
Field[] |
getFields() 返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。 |
Constructor<T> |
getConstructor(Class<?>... parameterTypes) 返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。(传入参数列表内参数的类型.class文件,型参)(通过参数列表来定位构造函数)
|
Constructor<?>[] |
getConstructors() 返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。 |
|
|
|
|
Field |
getDeclaredField(String name) 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。(只要声明即可获取,不管权限问题)
|
Field[] |
getDeclaredFields() 返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。(只要声明即可获取,不管权限问题)
|
Method |
getDeclaredMethod(String name, Class<?>... parameterTypes) 返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。(只要声明即可获取,不管权限问题)
|
Method[] |
getDeclaredMethods() 返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。 |
Constructor<T> |
getDeclaredConstructor(Class<?>... parameterTypes) 返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。(只要声明即可获取,不管权限问题)
|
Constructor<?>[] |
getDeclaredConstructors() 返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。(只要声明即可获取,不管权限问题)
|
(1)获取该类对象方法
<1>.方法1:
通过Object中的getClass()方法获取本类对象,不过前提是必须要有对象,使用的是非静态方法
Class<?> |
getClass() 返回此 Object 的运行时类。 |
<1>.方法2:
通过java任意数据类型都有一个.clsss字节码文件描述这一特性,任意数据类型都有一个静态成员class,例如int.class。来获取本类对象
例如:Class clazz = Person.class; 或者 Class clazz = int.class;
还是必须先要知道类,也就是类名,这个只是通过对象的静态属性
<1>.方法3:
通过该类的静态方法获取本类对象,最常用
static Class<?> |
forName(String className) 返回与带有给定字符串名的类或接口相关联的 Class 对象。 |
(2)建立Class对象所表示类的实例
<1>.可以通过Class类的newInstance()方法。只可以通过空参数够赞函数来构造
注1:InstantiationException是实例化失败异常,通常是没有空参数构造函数所致
注2:IllegalAccessException是访问权限不够时会抛出的异常
T |
newInstance() 创建此 Class 对象所表示的类的一个新实例。 |
<2>.可以通过Class类中方法获取构造函数对象,来对对象进行构造。并且可以通过制定构造函数对对对象进行初始化
3.2 Constructor类
方法摘要 | |
---|---|
T |
newInstance(Object... initargs) 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。(传入实际参数)
|
package cn.doing.reflect;
import java.lang.reflect.Constructor;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
public class ReflectConstructor {
private Class<Person> clazz;
//反射public Person(){}
@SuppressWarnings("unchecked")
@Test
public void test1() throws Exception {
clazz = (Class<Person>) Class.forName("cn.doing.reflect.Person");
Constructor<Person> c = clazz.getConstructor();
Person p = c.newInstance();
System.out.println(p.aa);
}
//反射public Person(String name){}
@SuppressWarnings("unchecked")
@Test
public void test2() throws Exception {
clazz = (Class<Person>) Class.forName("cn.doing.reflect.Person");
Constructor<Person> con = clazz.getConstructor(String.class);
Person p = con.newInstance("*");
System.out.println(p.aa);
}
//反射public Person(String name,int age){}
@SuppressWarnings("unchecked")
@Test
public void test3() throws Exception {
clazz = (Class<Person>) Class.forName("cn.doing.reflect.Person");
Constructor<Person> con = clazz.getConstructor(String.class,int.class);
Person p = con.newInstance("于泽",14);
System.out.println(p.aa);
}
//反射private Person(Set s){}
@SuppressWarnings("unchecked")
@Test
public void test4() throws Exception {
clazz = (Class<Person>) Class.forName("cn.doing.reflect.Person");
Constructor<Person> con = clazz.getDeclaredConstructor(Set.class);
con.setAccessible(true);
Person p = con.newInstance(new HashSet<String>());
System.out.println(p.aa);
}
//通过另一种方法反射public Person(){},通过Class类中提供的newInstance()方法创建空参数的实例
@SuppressWarnings("unchecked")
@Test
public void test5() throws Exception {
clazz = (Class<Person>) Class.forName("cn.doing.reflect.Person");
Person p = clazz.newInstance();
System.out.println(p.aa);
}
}
3.3 Field类
方法摘要 | |
---|---|
void |
setObject obj, Object value) 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。(修改指定对象的这个字段值)
|
Object |
get(Object obj) 返回指定对象上此 Field 表示的字段的值。 |
Class<?> |
getType() 返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型。 |
package cn.doing.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import org.junit.Test;
public class ReflectField {
private Person p;
//反射空参数构造函数创建对象
@Test
public void newInstanceTest() throws Exception{
Class<?> clazz = Class.forName("cn.doing.reflect.Person");
Constructor<?> con = clazz.getConstructor();
p = (Person) con.newInstance();
}
//反射类的字段public String aa = "111";
@Test
public void getField1() throws Exception{
newInstanceTest();
Class<?> clazz = Class.forName("cn.doing.reflect.Person");
Field f = clazz.getField("aa");
System.out.println(f.get(p));
}
//反射类的字段private String bb = "aaa";
@Test
public void getField2() throws Exception{
newInstanceTest();
Class<?> clazz = Class.forName("cn.doing.reflect.Person");
Field f = clazz.getDeclaredField("bb");
f.setAccessible(true);
f.set(p, "xxxxxxxxxxxxx");
Object value = f.get(p);
Class type = f.getType();
if(type.equals(String.class)){
String svalue = (String) value;
System.out.println(svalue);
}
}
//反射类的字段private static int cc = 111222222;
@Test
public void getField3() throws Exception{
//newInstanceTest();
Class<?> clazz = Class.forName("cn.doing.reflect.Person");
Field f = clazz.getDeclaredField("cc");
f.setAccessible(true);
Object value = f.get(null);
Class type = f.getType();
if(type.equals(int.class)){
int ivalue = (Integer) value;
System.out.println(ivalue);
}
}
}
3.4 Method类
方法摘要 | |
---|---|
Object |
invoke(Object obj, Object... args) 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。(静态方法传入对象为null即可)
|
package cn.doing.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import org.junit.Test;
public class ReflectMethod {
private Person p ;
//反射类中的空参数的构造函数建立对象
@Test
public void newInstanceTest() throws Exception{
Class<?> clazz = Class.forName("cn.doing.reflect.Person");
Constructor<?> con = clazz.getConstructor();
p = (Person) con.newInstance();
}
//反射类中方法public void function(){}
@Test
public void getMethod1() throws Exception{
newInstanceTest();
Class<?> clazz = Class.forName("cn.doing.reflect.Person");
Method m = clazz.getMethod("function",null);
m.invoke(p, null);
}
//反射类中方法public int function(String name){}
@Test
public void getMethod2() throws Exception{
newInstanceTest();
Class<?> clazz = Class.forName("cn.doing.reflect.Person");
Method m = clazz.getMethod("function", String.class);
m.invoke(p, "王逊");
}
//反射类中方法public Class[] function(int i,String[] args){}
@SuppressWarnings("rawtypes")
@Test
public void getMethod3() throws Exception{
newInstanceTest();
Class<?> clazz = Class.forName("cn.doing.reflect.Person");
Method m = clazz.getMethod("function", int.class,String[].class);
Class[] arr = (Class[]) m.invoke(p, 1,new String[]{});
System.out.println(arr);
}
//反射类中方法public static void funtion(long l){}
@Test
public void getMethod4() throws Exception{
//newInstanceTest();
Class<?> clazz = Class.forName("cn.doing.reflect.Person");
Method m = clazz.getMethod("function", long.class);
m.invoke(null,111);
}
//反射类中方法private boolean funtion1(boolean flag){}
@Test
public void getMethod5() throws Exception{
newInstanceTest();
Class<?> clazz = Class.forName("cn.doing.reflect.Person");
Method m = clazz.getDeclaredMethod("function1", boolean.class);
m.setAccessible(true);
System.out.println(m.invoke(p, true));
}
//反射类中主方法public static void main(String[] args) {}
@Test
public void getMethod6() throws Exception{
//newInstanceTest();
Class<?> clazz = Class.forName("cn.doing.reflect.Person");
Method m = clazz.getMethod("main", String[].class);
m.invoke(null, (Object)new String[]{"12","123"});
}
}
3.5 AccessibleObject类
注1:Field类、Constructor类、Method类的基类,定义共性内容
方法摘要 | |
---|---|
void |
setAccessible(boolean flag) 将此对象的 accessible 标志设置为指示的布尔值。(暴力反射,对象在使用时应该取消Java语言访问检查) |
3.6 反射主函数(注意)
当反射主函数时一定要注意在调用invoke(obj,args)时,不能只传入一个new String["1","aabb"],因为Java可变参数的向下兼容特性,导致会把这个数组拆分为两个字符串类型参数
二.枚举
1.适用环境
当需要让方法传入数据不能任意时,可以用自定义类来解决,类不能加你对象并且类中封装了你需要的值。JDK1.5以后可以用枚举类型来解决这一问题
2.知识点
3.Enum类
方法摘要 | ||
---|---|---|
String |
name() 返回此枚举常量的名称,在其枚举声明中对其进行声明。 |
|
int |
ordinal() 返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。 |
|
static
|
valueOf(Class<T> enumType, String name) 返回带指定名称的指定枚举类型的枚举常量。(将一个字符串转成一个枚举,用法:可以判定这个字符串是否是枚举值,不是的话会抛出异常。很简单的判定字符串的合法性) |
4.代码演示
package cn.doing.enumeration;
public enum EnumClass {//枚举
A("100-90"){//A B C D都分别代表枚举值并且都是本类对象
@Override
public String getLocalValue() {
// TODO Auto-generated method stub
return null;
}
},B("89-80") {//构造对象
@Override
public String getLocalValue() {//复写抽象方法
// TODO Auto-generated method stub
return null;
}
},C("79-70") {
@Override
public String getLocalValue() {
// TODO Auto-generated method stub
return null;
}
},D("69-60") {
@Override
public String getLocalValue() {
// TODO Auto-generated method stub
return null;
}
},E("59-0") {
@Override
public String getLocalValue() {
// TODO Auto-generated method stub
return null;
}
};
private String value;//枚举字段
private EnumClass(String value){//枚举构造函数
this.value = value;
}
public String getValue(){//枚举抽象方法
return value;
}
public abstract String getLocalValue();
}