Java基础——反射、枚举

时间:2023-02-16 10:55:52

一.反射

1.使用情景

当你做程序开发时,你会发现定义接口,可以提高程序扩展性,扩展功能类实现接口即可。可是你会发现源码中只有引用型变量不用修改了而已,扩展功能时不能避免的就是建立功能类的对象,对象是必须要建立的。这时就有了反射技术出现解决了这一问题,只要你把功能类类名定义在一个指定配置文件中,你不用修改任何源程序代码的情况下完成功能的扩展反射的出现大大提高了程序的扩展性

Java基础——反射、枚举

2.解释

反射就是加载类,并解刨出类的各个组成部分

3.描述

3.1 Class类的含义

(1)Class类是对*.class文件共性内容向上抽取后得到的类,是一个描述类的类。就像多个对象都是同一个类构造的一样

(2)字段(成员变量)、构造函数、成员函数都封装为了对象存储在Class类中,来对字节码文件进行统一的描述

(3)重点:每一个Class对象都单单指一个*.class文件

Java基础——反射、枚举

3.2 使用方法

方法摘要
 Field getField(String name) 
          返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。通过变量名来定位哪一个变量
 Field[] getFields() 
          返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
 Constructor<T> getConstructor(Class<?>... parameterTypes) 
          返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。传入参数列表内参数的类型.class文件,型参)(通过参数列表来定位构造函数)
 Constructor<?>[] getConstructors() 
          返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。

 Method

getMethod(String name, Class<?>... parameterTypes) 
          返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。通过方法名和参数列表定位哪一个函数

 Method[]

getMethods() 
          返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。

 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.知识点

(1)意义:枚举类也是一种特殊形式的Java类
(2)特点:枚举每一个枚举值都代表一个枚举类的实例对象,并且也可以声明属性、方法、构造函数,构造函数必须是私有的。还有枚举类也可以继承实现类和接口
(3)JDK1.5以后swich选择语句可以接收枚举类型
(4)枚举值只有一个的情况下,则可以视为简单的单利设计模式

3.Enum类

方法摘要
 String name() 
          返回此枚举常量的名称,在其枚举声明中对其进行声明。
 int ordinal() 
          返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。
static
<T extends Enum<T>> 
T
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();
}