:Java之反射和枚举
Posted 快乐江湖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了:Java之反射和枚举相关的知识,希望对你有一定的参考价值。
文章目录
一:反射
(1)反射的定义
Java反射(reflection):反射机制是指在运行状态中,对于任意一个类,我们都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性。这种动态获取信息以及动态调用对象方法的功能称之为Java的反射机制
- 在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法
- 反射最重要的用途就是开发各种通用框架,比如在spring中,我们将所有的类Bean交给spring容器管理,无论是XML配置Bean还是注解配置,当我们从容器中获取Bean来依赖注入时,容器会读取配置,而配置中给的就是类的信息,spring根据这些信息,需要创建那些Bean,spring就动态的创建这些类
Java程序中许多对象在运行时会出现两种类型:运行时类型和编译时类型,利用反射就能判断出该对象和类属于哪些类
- 例如
Person p = new Student()
中,p
在编译时类型为Person
而运行时类型为Student
(2)反射相关类及方法
A:类
类名 | 用途 |
---|---|
Class 类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field 类 | 代表类的成员变量/类的属性 |
Method 类 | 代表类的方法 |
Constructor 类 | 代表类的构造方法 |
B:方法
①:Class
类中的相关方法
类名 | 用途 |
---|---|
getClassLoader() | 获得类加载器 |
getDeclaredClasses() | 返回一个数组,数组中包含该类中所有类和接口类的对象(包括私有) |
forName(String className) | 根据类名返回类的对象 |
newInstance() | 创建类的实例 |
getName() | 获得类的完整路径名字 |
②:Field
类中的相关方法
类名 | 用途 |
---|---|
getField(String name) | 获得某个公有的属性对象 |
getFields() | 获得所有公有的属性对象 |
getDeclaredField(String name) | 获得某个属性对象 |
getDeclaredFields() | 获得所有属性对象 |
③:获得类中注解相关方法
类名 | 用途 |
---|---|
getAnnotation(Class annotationClass) | 返回该类中与参数类型匹配的公有注解对象 |
getAnnotations() | 返回该类所有的公有注解对象 |
getDeclareAnnotation(Class annotationClass) | 返回该类中与参数类型匹配的所有注解对象 |
getDeclaredAnnotations() | 返回该类所有的注解对象 |
④:获得类中构造器相关方法
类名 | 用途 |
---|---|
getConstructor(Class...<?> parameter Types) | 获得该类中与参数类型匹配的公有构造方法 |
getConstructors() | 获得该类的所有公有构造方法 |
getDeclaredConstructor(Class...<?> parameter Types ) | 获得该类中与参数类型匹配的构造方法 |
getDeclaredConstructors() | 获得该类所有构造方法 |
⑤:获得类中方法的相关方法
类名 | 用途 |
---|---|
getMethod(String name, Class...<?> parameter Types) | 获得该类某个公有的方法 |
getMethods() | 获得该类所有公有的方法 |
getDeclaredMethod(String name, Class...<?> parameter Types ) | 获得该类某个方法 |
getDeclaredMethods() | 获得该类所有方法 |
(3)反射使用
以如下Student
类为例
class Student
private String name = "zhangsan";
public int age = 19;
public Student()
System.out.println("调用无参构造方法");
private Student(String name, int age)
this.name = name;
this.age = age;
System.out.println("调用含参构造方法(私有)");
private void eat()
System.out.println("调用私有eat方法");
private void sleep()
System.out.println("调用私有sleep方法");
private void function(String str)
System.out.println(str);
@Override
public String toString()
return "Student" +
"name='" + name + '\\'' +
", age=" + age +
'';
A:获取Class对象
获取Class
对象:使用反射之前首先需要拿到当前待反射的类的Class
对象,然后通过Class
对象的核心方法,达到反射目的。主要有以下三种方法
- 第一种:使用
Class.forName
(“类的全路径名”) - 第二种(推荐):使用
.class
方法 - 第三种(较多使用):使用类对象的
getClass()
方法
如下
public class TestDemo
public static void main(String[] args) throws ClassNotFoundException
//第一种:通过Class对象的forName静态方法获取,但可能抛出ClassNotFoundException异常,需要进行捕获
try
Class<?> c1 = Class.forName("Student");
catch(ClassNotFoundException e)
e.printStackTrace();
//第二种:通过类名.class方式获取
Class<?> c2 = Student.class;
//第三种:通过getClass获取
Student student = new Student();
Class<?> c3 = student.getClass();
B:反射使用示例
反射使用示例如下,开始学习时可能会感觉语法繁琐,但是熟悉之后还是感觉比较容易的。从下面的例子中,大家可以体会到反射的作用非常强大
public class TestDemo
//创建类的实例
public void reflectNewInstance()
try
Class<?> c = Class.forName("Student");
Student student = (Student) c.newInstance();
System.out.println(student);
catch (ClassNotFoundException e)
throw new RuntimeException((e));
catch (InstantiationException e)
throw new RuntimeException(e);
catch (IllegalAccessException e)
throw new RuntimeException(e);
//反射私有构造方法
public void reflectPrivateConstructor()
try
Class<?> c = Class.forName("Student");
//拿到带有两个参数的私有构造方法
Constructor<?> constructor = c.getDeclaredConstructor(String.class, int.class);
//只有设置为true后下一步才可以生效
constructor.setAccessible(true);
//使用该构造方法构造对象
Student student = (Student) constructor.newInstance("李四", 18);
System.out.println(student);
catch (ClassNotFoundException e)
throw new RuntimeException(e);
catch (NoSuchMethodException e)
throw new RuntimeException(e);
catch (InvocationTargetException e)
throw new RuntimeException(e);
catch (InstantiationException e)
throw new RuntimeException(e);
catch (IllegalAccessException e)
throw new RuntimeException(e);
//反射私有属性
public void reflectPrivateField()
try
Class<?> c = Class.forName("Student");
Student student = (Student) c.newInstance();
//获取私有属性name
Field field = c.getDeclaredField("name");
//只有设置为true后下一步才可以生效
field.setAccessible(true);
//修改该属性
field.set(student, "王麻子");
System.out.println(student);
catch (ClassNotFoundException e)
throw new RuntimeException(e);
catch (InstantiationException e)
throw new RuntimeException(e);
catch (IllegalAccessException e)
throw new RuntimeException(e);
catch (NoSuchFieldException e)
throw new RuntimeException(e);
//反射私有方法
public void reflectPrivateMethod()
try
Class<?> c = Class.forName("Student");
Student student = (Student) c.newInstance();
//获取私有方法function
Method method = c.getDeclaredMethod("function", String.class);
//只有设置为true后下一步才可以生效
method.setAccessible(true);
//传参给该私有方法
method.invoke(student, "通过反射给该方法传参");
System.out.println(student);
catch (ClassNotFoundException e)
throw new RuntimeException(e);
catch (InstantiationException e)
throw new RuntimeException(e);
catch (IllegalAccessException e)
throw new RuntimeException(e);
catch (NoSuchMethodException e)
throw new RuntimeException(e);
catch (InvocationTargetException e)
throw new RuntimeException(e);
public static void main(String[] args)
TestDemo testDemo = new TestDemo();
testDemo.reflectNewInstance(); // 利用反射创建对象
System.out.println("----------------------------------");
testDemo.reflectPrivateConstructor(); //利用反射调用私有构造方法并创建对象
System.out.println("----------------------------------");
testDemo.reflectPrivateField(); //利用反射获取私有属性并修改
System.out.println("----------------------------------");
testDemo.reflectPrivateMethod(); //利用反射调用私有方法并传参
System.out.println("----------------------------------");
(4)反射优缺点
优点:
- 对于任意一个类都能知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法
- 提高灵活性、增强扩展能力、降低耦合性、提高自适应能力
- 可以应用在很多流行框架中
缺点:
- 反射可能会导致效率降低
- 反射会使维护变得困难,使代码复杂
二:枚举
(1)枚举基本概念
枚举:Java枚举是一个特殊的类,一般表示一组常量,使用关键字enum
来定义,常量间使用逗号分隔
- 注意:自定义的枚举类默认继承
java.lang.Enum
public enum Color
RED, BLACK, GREEN;
(2)枚举使用
A:在switch语句中
public enum Color
RED, BLACK, GREEN, WHITE;
public class TestDemo
public static void main(String[] args)
Color color = Color.BLACK;
switch(color)
case RED:
System.out.println("红色");
break;
case BLACK:
System.out.println("黑色");
break;
case GREEN:
System.out.println("绿色");
break;
case WHITE:
System.out.println("白色");
break;
default:
System.out.println("未知颜色");
break;
B:常用方法
Enum
类常用方法如下表
方法名称 | 描述 |
---|---|
values() | 以数组形式返回枚举类型的所有成员 |
ordinal() | 获取枚举成员的索引位置 |
valueOf() | 将普通字符串转化为枚举实例 |
compareTo() | 比较两个枚举成员在定义时的顺序 |
如下例
public enum Color
RED, BLACK, GREEN, WHITE;
public class TestDemo
public static void main(String[] args)
//以数组形式返回枚举类型的所有成员,然后遍历输出枚举成员和其序号
Color[] enums = Color.values();
for(int i = 0; i < enums.length; i++)
System.out.println(enums[i] + "序号" + enums[i].ordinal());
//通过返回枚举实例
System.out.println("======================================");
Color green = Color.valueOf("GREEN");
System.out.println(green);
//比较枚举成员顺序大小(序号大小)
System.out.println("======================================");
Color red = Color.valueOf("RED");
Color black = Color.valueOf("BLACK");
System.out.println(red.compareTo(black) < 0 ? "RED<BLACK" : "RED>BLACK");
C:关于构造方法
- 需要注意,枚举构造方法默认为
private
public enum Color
RED("red", 7),
BLACK("black",3),
GREEN("green", 11),
WHITE("white", 0);
public final String color;
public final int ordinal;
Color(String color, int ordinal)
this.color = color;
this.ordinal = ordinal;
以上是关于:Java之反射和枚举的主要内容,如果未能解决你的问题,请参考以下文章