31反射(获取Class实例剖析运行时类的完整结构读取properties文件反射创建类越过泛型检查)枚举
Posted shawnyue-08
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了31反射(获取Class实例剖析运行时类的完整结构读取properties文件反射创建类越过泛型检查)枚举相关的知识,希望对你有一定的参考价值。
反射
1、Java反射机制概述
- 反射机制允许程序在执行期通过Reflection API取得任何类的内部信息,并能直接操作任何对象的内部属性和方法;
- 加载完类后,在方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息,这个对象就像一面镜子,透过这个镜子可以看到类的结构,所以我们称为反射。
反射相关的主要API
- java.lang.Class:代表一个类
- java.lang.reflect.Method:代表类的方法
- java.lang.reflect.Field:代表类的成员变量
- java.lang.reflect.Constructor:代表类的构造器
- ...
2、获取Class类的实例
关于类的加载过程:
程序经过javac.exe
命令后,生成字节码文件(.class),使用java.exe
命令对某个字节码文件进行解释运行,相当于将某个字节码文件加载到内存中,此过程称为类的加载。
加载到内存中的类,称为运行时类,作为Class类的实例。
获取Class实例的四种方式:
package org.westos.demo;
/**
* @author lwj
* @date 2020/6/14 9:26
*/
public class Student {
}
package org.westos.demo;
/**
* 获取Class类型的实例
* @author lwj
* @date 2020/6/14 9:25
*/
public class MyTest {
public static void main(String[] args) {
//方式一、Object类的getClass()方法
Student student = new Student();
Class<? extends Student> studentClass = student.getClass();
Class<? extends Student> studentClass1 = student.getClass();
//字节码文件对象只有一个
System.out.println(studentClass == studentClass1);
//true
//方式二、通过Class类的静态方法forName(String s),传递类的全限定类名:包名 + 类名
try {
Class<?> aClass = Class.forName("org.westos.demo.Student");
System.out.println(aClass);
//class org.westos.demo.Student
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//方式三、类的class属性
Class<Student> studentClass2 = Student.class;
System.out.println(studentClass2);
//class org.westos.demo.Student
//方式四、类加载器
try {
Class<?> aClass = MyTest.class.getClassLoader().loadClass("org.westos.demo.Student");
System.out.println(aClass);
//class org.westos.demo.Student
System.out.println(aClass == studentClass);
//true
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Class类
- Class对象只能由系统建立对象;
- 一个加载的类在JVM中只会有一个Class实例;
- 一个Class对象对应的是一个加载到JVM中的一个.class文件;
哪些类型可以有Class对象?
- class(外部类、成员(成员内部类、静态内部类)、局部内部类、匿名内部类)
package org.westos.demo;
import java.util.Comparator;
/**
* 哪些类型可以有Class对象
* class
* @author lwj
* @date 2020/6/14 9:37
*/
public class MyTest2 {
public static void main(String[] args) {
Class<Object> objectClass = Object.class;
System.out.println(objectClass);
//class java.lang.Object
Class<? extends Runnable> runnableDemo = new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类");
}
}.getClass();
System.out.println(runnableDemo);
//class org.westos.demo.MyTest2$1
//匿名内部类的.class字节码文件名称:MyTest2$1.class
Class<? extends Comparator<Integer>> aClass = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
}.getClass();
System.out.println(aClass);
//class org.westos.demo.MyTest2$2
//数字是声明顺序
Class<Person.Inner> innerClass = Person.Inner.class;
System.out.println(innerClass);
//class org.westos.demo.Person$Inner
new Person().method();
Class<Person.StaticInnerClass> staticInnerClassClass = Person.StaticInnerClass.class;
System.out.println(staticInnerClassClass);
//class org.westos.demo.Person$StaticInnerClass
}
}
class Person {
public class Inner {
public int num = 10;
}
public void method() {
class LocalInnerClass {
public int res = 20;
}
Class<LocalInnerClass> aClass = LocalInnerClass.class;
System.out.println(aClass);
//class org.westos.demo.Person$1LocalInnerClass
//数字是为了区分重名的局部内部类
}
public static class StaticInnerClass {
}
}
- interface接口
- []数组
标识字符 | 含义 |
---|---|
B | 基本类型byte |
C | 基本类型char |
D | 基本类型double |
F | 基本类型float |
I | 基本类型int |
J | 基本类型long |
L classname; | 对象类型 |
S | 基本类型short |
Z | 基本类型boolean |
[ | 数组对象 |
package org.westos.demo;
import java.util.Map;
import java.util.concurrent.Callable;
/**
* interface、[]
* @author lwj
* @date 2020/6/14 9:52
*/
public class MyTest3 {
public static void main(String[] args) {
Class<Runnable> runnableClass = Runnable.class;
System.out.println(runnableClass);
//interface java.lang.Runnable
Class<Callable> callableClass = Callable.class;
System.out.println(callableClass);
//interface java.util.concurrent.Callable
Class<Map.Entry> entryClass = Map.Entry.class;
System.out.println(entryClass);
//interface java.util.Map$Entry
System.out.println(int[].class);
//class [I
System.out.println(byte[].class);
//class [B
System.out.println(char[].class);
//class [C
System.out.println(short[].class);
//class [S
System.out.println(float[].class);
//class [F
System.out.println(double[].class);
//class [D
System.out.println(boolean[].class);
//class [Z
System.out.println(long[].class);
//class [J
System.out.println(String[].class);
//class [Ljava.lang.String;
System.out.println(Integer[].class);
//class [Ljava.lang.Integer;
System.out.println(Object[].class);
//class [Ljava.lang.Object;
System.out.println(int[][].class);
//class [[I
System.out.println(String[][].class);
//class [[Ljava.lang.String;
System.out.println(Integer[][].class);
//class [[Ljava.lang.Integer;
}
}
- enum枚举
- annotation注解
- 基本数据类型
- void
package org.westos.demo;
import org.westos.demo2.MyAnnotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
/**
* enum枚举、annotation注解、基本数据类型、void
* @author lwj
* @date 2020/6/14 12:55
*/
public class MyTest4 {
public static void main(String[] args) {
Class<ElementType> elementTypeClass = ElementType.class;
//public enum ElementType {}
System.out.println(elementTypeClass);
//class java.lang.annotation.ElementType
//枚举继承java.lang.Enum类
Class<Target> targetClass = Target.class;
System.out.println(targetClass);
//interface java.lang.annotation.Target
//注解其实是接口
Class<MyAnnotation> myAnnotationClass = MyAnnotation.class;
System.out.println(myAnnotationClass);
//interface org.westos.demo2.MyAnnotation
Class<Integer> integerClass = int.class;
System.out.println(integerClass);
//int
Class<Byte> byteClass = byte.class;
System.out.println(byteClass);
//byte
Class<Void> voidClass = void.class;
System.out.println(voidClass);
//void
Class<Class> classClass = Class.class;
System.out.println(classClass);
//class java.lang.Class
int[] a = new int[10];
int[] b = new int[100];
Class<? extends int[]> aClass = a.getClass();
Class<? extends int[]> bClass = b.getClass();
System.out.println(aClass == bClass);
//true
//只要数组的元素类型和维度一样,就是一个Class
}
}
3、剖析运行时类的完整结构
Constructor、Field、Method、SuperClass、Interface、Annotation。
1、提供更丰富的Student类
接口:
package org.westos.demo2;
/**
* @author lwj
* @date 2020/6/14 10:11
*/
public interface MyInterface {
/** 接口信息 */
void info();
}
注解:
package org.westos.demo2;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author lwj
* @date 2020/6/14 10:12
*/
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "Hello Reflection";
}
父类:
package org.westos.demo2;
import java.io.Serializable;
/**
* @author lwj
* @date 2020/6/14 10:15
*/
public class Creature implements Serializable {
private static final long serialVersionUID = -8153816869384698294L;
private char gender;
public double weight;
private void breath() {
System.out.println("生物呼吸");
}
public void eat() {
System.out.println("生物吃东西");
}
}
Student类:
package org.westos.demo2;
/**
* @author lwj
* @date 2020/6/14 10:10
*/
@MyAnnotation("Student")
public class Student extends Creature implements Comparable<Student>, MyInterface{
@MyAnnotation(value = "name")
private String name;
int age;
public int id;
public Student() {
System.out.println("空参构造");
}
@MyAnnotation("Student Constructor")
public Student(String name) {
this.name = name;
}
private Student(String name, int age) {
this.name = name;
this.age = age;
}
@MyAnnotation
private String show(String nation) {
System.out.println("我的国籍是" + nation);
return nation;
}
public String display(String interesting) {
return interesting;
}
@Override
public int compareTo(Student o) {
return 0;
}
@Override
public void info() {
System.out.println("MyInterface接口的info方法实现");
}
@Override
public String toString() {
return "Student{" +
"name=‘" + name + ‘‘‘ +
", age=" + age +
"} ";
}
}
Constructor
构造器不参与继承,子类可以通过super关键字来访问父类的构造方法。
package org.westos.demo2;
import java.lang.reflect.Constructor;
/**
* 通过反射剖析一个类的构成
* @author lwj
* @date 2020/6/14 9:59
*/
public class MyDemo {
public static void main(String[] args) {
//构造方法 Constructor、成员变量 Field、成员方法 Method
//这三个组成部分也会被看成一个类型
Class<Student> studentClass = Student.class;
Constructor<?>[] constructors = studentClass.getConstructors();
//获取当前字节码文件对象中所有声明为public的构造器
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
//public org.westos.demo2.Student(java.lang.String)
//public org.westos.demo2.Student()
}
Constructor<?>[] declaredConstructors = studentClass.getDeclaredConstructors();
//获取当前字节码文件对象中所有构造器
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
//private org.westos.demo2.Student(java.lang.String,int)
//public org.westos.demo2.Student(java.lang.String)
//public org.westos.demo2.Student()
}
}
}
package org.westos.demo2;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
/**
* 获取Class对象上的注解,获取构造器上的注解
* @author lwj
* @date 2020/6/14 10:47
*/
public class MyDemo3 {
public static void main(String[] args) throws NoSuchMethodException {
Class<Student> studentClass = Student.class;
Constructor<Student> declaredConstructor = studentClass.getDeclaredConstructor(String.class);
Annotation[] declaredAnnotations = declaredConstructor.getDeclaredAnnotations();
for (Annotation declaredAnnotation : declaredAnnotations) {
System.out.println(declaredAnnotation);
//@org.westos.demo2.MyAnnotation(value=Student Constructor)
}
Annotation[] declaredAnnotations1 = studentClass.getDeclaredAnnotations();
for (Annotation annotation : declaredAnnotations1) {
System.out.println(annotation);
//@org.westos.demo2.MyAnnotation(value=Student)
}
}
}
通过Constructor对象来创建对象
package org.westos.demo2;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* 通过Constructor对象创建对象
* @author lwj
* @date 2020/6/14 10:27
*/
public class MyDemo2 {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<Student> studentClass = Student.class;
Constructor<Student> constructor = studentClass.getConstructor();
//获取public的无参构造器对象
Student student = constructor.newInstance();
System.out.println(student);
//Student{name=‘null‘, age=0}
Constructor<Student> constructor1 = studentClass.getConstructor(String.class);
//获取public的一个参数的构造器对象
Student student1 = constructor1.newInstance("张三");
System.out.println(student1);
//Student{name=‘张三‘, age=0}
Constructor<Student> declaredConstructor = studentClass.getDeclaredConstructor(String.class, int.class);
//获取private的两个参数的构造器对象
declaredConstructor.setAccessible(true);
Student student2 = declaredConstructor.newInstance("李四", 24);
System.out.println(student2);
//Student{name=‘李四‘, age=24}
}
}
通过Class对象创建对象(空参构造)
package org.westos.demo2;
/**
* 通过空参创建对象
* @author lwj
* @date 2020/6/14 11:01
*/
public class MyDemo4 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
Class<Student> studentClass = Student.class;
Student student = studentClass.newInstance();
System.out.println(student);
//Student{name=‘null‘, age=0}
}
}
Field
方法 | 描述 |
---|---|
Field[] getFields() | 获取本类、父类中声明为public的属性 |
Field[] getDeclaredFields() | 获取本类中声明的所有属性 |
package org.westos.demo2;
import java.lang.reflect.Field;
/**
* 通过反射剖析一个类的组成
* Field
* @author lwj
* @date 2020/6/14 10:55
*/
public class MyTest {
public static void main(String[] args) {
Class<Student> studentClass = Student.class;
Field[] fields = studentClass.getFields();
//获取本类中所有声明为public的属性,包括从父类继承的属性
for (Field field : fields) {
System.out.println(field);
//public int org.westos.demo2.Student.id
//public double org.westos.demo2.Creature.weight
}
Field[] declaredFields = studentClass.getDeclaredFields();
//获取本类中所有的属性,包括私有属性,但是不包括父类属性
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
//private java.lang.String org.westos.demo2.Student.name
//int org.westos.demo2.Student.age
//public int org.westos.demo2.Student.id
}
}
}
package org.westos.demo2;
import java.lang.reflect.Field;
/**
* Field
* @author lwj
* @date 2020/6/14 11:07
*/
public class MyTest2 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchFieldException {
//设置/获取成员变量的值
Class<Student> studentClass = Student.class;
Student student = studentClass.newInstance();
student.age = 23;
//student.name 没有提供set/get方法,不能直接访问
Field name = studentClass.getDeclaredField("name");
//获取name字段的Field对象
name.setAccessible(true);
name.set(student, "张三");
//设置student对象的name字段的值
System.out.println(student);
//Student{name=‘张三‘, age=23}
String o = (String) name.get(student);
//获取student对象的name属性
System.out.println(o);
//张三
}
}
package org.westos.demo2;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
/**
* 获取Field字段上的注解
* @author lwj
* @date 2020/6/14 11:19
*/
public class MyTest3 {
public static void main(String[] args) throws NoSuchFieldException {
Class<Student> studentClass = Student.class;
Field name = studentClass.getDeclaredField("name");
Annotation[] declaredAnnotations = name.getDeclaredAnnotations();
for (Annotation declaredAnnotation : declaredAnnotations) {
System.out.println(declaredAnnotation);
//@org.westos.demo2.MyAnnotation(value=name)
}
}
}
Method
方法 | 描述 |
---|---|
Method[] getMethods() | 获取本类、父类中声明为public的方法 |
Method[] getDeclaredMethods() | 获取本类所有声明的方法 |
package org.westos.demo2;
import java.lang.reflect.Method;
/**
* Method
* @author lwj
* @date 2020/6/14 13:35
*/
public class Test {
public static void main(String[] args) {
Class<Student> studentClass = Student.class;
Method[] methods = studentClass.getMethods();
for (Method method : methods) {
System.out.println(method);
//获取当前类,以及所有父类(Creature、Object)中的public修饰的方法
}
Method[] declaredMethods = studentClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
//获取当前类中所有方法,包括私有方法,但是不包括父类的方法
}
}
}
package org.westos.demo2;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 反射调用方法
* @author lwj
* @date 2020/6/14 13:48
*/
public class Test3 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<Student> studentClass = Student.class;
Student student = studentClass.newInstance();
Method display = studentClass.getDeclaredMethod("display", String.class);
String hello = (String) display.invoke(student, "Hello");
//调用public的方法
System.out.println(hello);
//Hello
Method show = studentClass.getDeclaredMethod("show", String.class);
show.setAccessible(true);
String nation = (String) show.invoke(student, "中国");
//调用private的方法
System.out.println(nation);
//中国
}
}
父类、接口、包
package org.westos.demo2;
/**
* 父类、接口、包
* @author lwj
* @date 2020/6/14 13:20
*/
public class Demo {
public static void main(String[] args) {
Class<Student> studentClass = Student.class;
Class<? super Student> superclass = studentClass.getSuperclass();
System.out.println(superclass);
//class org.westos.demo2.Creature
Class<?>[] interfaces = studentClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
System.out.println(anInterface);
//interface java.lang.Comparable
//interface org.westos.demo2.MyInterface
}
Package aPackage = studentClass.getPackage();
System.out.println(aPackage);
//package org.westos.demo2
}
}
4、反射的应用
Properties配置文件
driverClass=org.westos.demo3.Example1
methodName=eat
package org.westos.demo3;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* 练习
* @author lwj
* @date 2020/6/14 14:34
*/
public class MyTest {
public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//--->读取配置文件,Class.forName()
Properties properties = new Properties();
properties.load(new FileInputStream(new File("src/org/westos/demo3/config.properties")));
String driverClass = properties.getProperty("driverClass");
Class<?> aClass = Class.forName(driverClass);
Object o = aClass.newInstance();
String methodName = properties.getProperty("methodName");
Method declaredMethod = aClass.getDeclaredMethod(methodName);
declaredMethod.invoke(o);
//调用Example1类的eat()方法
}
}
class Example1 {
public void eat() {
System.out.println("eat fish");
}
}
class Example2 {
public void eat() {
System.out.println("eat meat");
}
}
泛型
package org.westos.demo3;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
/**
* 练习
* @author lwj
* @date 2020/6/14 14:45
*/
public class MyTest2 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//通过反射越过泛型检查
//泛型:只在编译期有效,运行期被擦除
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("100");
Class<? extends ArrayList> aClass = arrayList.getClass();
Method add = aClass.getDeclaredMethod("add", Object.class);
//获取add的Method对象
add.invoke(arrayList, 200);
//在运行期将Integer类型加入集合
add.invoke(arrayList, true);
System.out.println(arrayList);
//[100, 200, true]
}
}
枚举
1、枚举类的使用
类的对象只有有限个,确定的,比如季节:春季、夏季、秋季、冬季,当需要一组常量时,强烈建议使用枚举类。
枚举类的实现
- jdk1.5以前需要自定义枚举类;
- jdk1.5新增enum关键字用于定义枚举类
若枚举只有一个对象,则可以作为一种单例模式的实现方法。
在jdk1.5之前如何自定义枚举类?
- 私有化类的构造器,保证不能在类的外部创建对象;
- 在类的内部创建枚举类的实例,声明为
public static final
;
package org.westos.demo;
/**
* @author lwj
* @date 2020/6/14 16:36
*/
public class Season {
//自定义枚举类
private final String seasonName;
private Season(String seasonName) {
this.seasonName = seasonName;
}
public static final Season SPRING = new Season("春天");
public static final Season SUMMER = new Season("夏天");
public static final Season AUTUMN = new Season("秋天");
public static final Season WINTER = new Season("冬天");
public String getSeasonName() {
return seasonName;
}
}
测试类
package org.westos.demo;
/**
* @author lwj
* @date 2020/6/14 16:35
*/
public class MyTest {
public static void main(String[] args) {
Season spring = Season.SPRING;
String seasonName = spring.getSeasonName();
System.out.println(seasonName);
//春天
Season summer = Season.SUMMER;
Season autumn = Season.AUTUMN;
Season winter = Season.WINTER;
}
}
jdk1.5之后使用enum关键字定义枚举类
-
enum定义的枚举类,默认是abstract修饰的抽象类;
-
使用enum定义的枚举类默认继承了
java.lang.Enum
类(抽象类),因此不能再继承其他类; -
枚举类的构造器只能使用private关键字;
-
枚举类的所有实例必须在枚举类中显式列出(
,
分隔;
结尾),列出的实例系统会自动添加public static final
修饰; -
必须在枚举类的第一行声明枚举类对象;
-
jdk1.5中可以在switch表达式中使用Enum定义的枚举类的对象作为表达式,case语句中可以直接使用枚举值的名字,无需添加枚举类作为限定。
使用jdk1.5以前自定义枚举类时,把Object当作父类,重写toString()方法,而jdk1.5以后使用enum关键字定义枚举类,把java.lang.Enum
当作父类,不需要重写toString()方法。
package org.westos.demo2;
/**
* @author lwj
* @date 2020/6/14 16:52
*/
public enum Season {
SPRING,
SUMMER,
AUTUMN,
WINTER;
}
/*
等价于
class Season {
public static final Season SPRING = new Season();
public static final Season SUMMER = new Season();
public static final Season AUTUMN = new Season();
public static final Season WINTER = new Season();
private Season() {}
}
*/
测试类
package org.westos.demo2;
/**
* @author lwj
* @date 2020/6/14 16:56
*/
public class MyTest {
public static void main(String[] args) {
Season spring = Season.SPRING;
System.out.println(spring);
//SPRING
//Enum的toString()默认输出常量的名称
Season summer = Season.SUMMER;
System.out.println(summer);
//SUMMER
Season autumn = Season.AUTUMN;
System.out.println(autumn);
//AUTUMN
Season winter = Season.WINTER;
System.out.println(winter);
//WINTER
}
}
switch的参数类型可以为byte、short、int、char、Enum、String,其中Enum是jdk1.5以后新增的,String为jdk1.7新增的特性。
- case 后面跟的必须是常量;
- 执行顺序,先case判断,如果匹配成功,执行代码,直到break。
当switch的参数类型为枚举,case 枚举类型:
package org.westos.demo3;
import org.westos.demo2.Season;
/**
* @author lwj
* @date 2020/6/14 17:06
*/
public class MyTest {
public static void main(String[] args) {
switch (Season.SUMMER) {
case SPRING:
System.out.println("春天");
break;
case SUMMER:
System.out.println("夏天");
break;
case AUTUMN:
System.out.println("秋天");
break;
case WINTER:
System.out.println("冬天");
break;
}
}
}
当switch的参数类型是一个String类型时,比如下面的例子:
package org.westos.demo3;
/**
* @author lwj
* @date 2020/6/14 17:08
*/
public class MyTest2 {
public static void main(String[] args) {
switch ("aaa") {
case "aaa":
System.out.println("aaa");
break;
case "AAA":
System.out.println("AAA");
break;
case "bbb":
System.out.println("bbb");
break;
case "BBB":
System.out.println("BBB");
break;
}
}
}
以上是关于31反射(获取Class实例剖析运行时类的完整结构读取properties文件反射创建类越过泛型检查)枚举的主要内容,如果未能解决你的问题,请参考以下文章
大数据必学Java基础(九十):通过反射获取运行时类的完整结构