Java核心知识反射
Posted 烟锁迷城
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java核心知识反射相关的知识,希望对你有一定的参考价值。
1、定义
在程序运行中动态获取类的相关属性,这种动态获取类的内容以及动态调用对象的方法和获取属性的机制,就叫做JAVA的反射机制。
- 对于给定的一个类(class)对象,可以获得这个类(class)对象的所有属性和方法
- 对于给定的一个对象(new X <? extends Object>),都能够调用它的任意一个属性和方法。
2、优缺点
优点
- 增加程序的灵活性,避免固有逻辑写死到程序中
- 代码相对简洁,可以提高程序的可用性
代码示例:
public interface Ball {
void play();
}
public class FootBall implements Ball {
@Override
public void play() {
System.out.println("踢足球");
}
}
public class BasketBall implements Ball {
@Override
public void play() {
System.out.println("打篮球");
}
}
public class BallMain {
public static Ball getInstanceByKey(String key) {
String packageName = "com.thread.demo.bool.";
try {
return (Ball) Class.forName(packageName+key).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
public class Demo {
public static void main(String[] args) {
BallMain.getInstanceByKey("BasketBall").play();
}
}
缺点
- 相比于直接调用,反射有更大的性能开销
- 暴露类的内部结构,有安全隐患
调用native方法和在newInstance时,会进行安全检查,这些让性能下降。
3、具体操作
3.1、基本操作
3.1.1、获取类对象的四种方式
Class<User> aClass1 = User.class;
Class<?> aClass2 = Class.forName("com.lc.app.demo.User");
Class<? extends User> aClass3 = new User().getClass();
Class<?> aClass4 = User.class.getClassLoader().loadClass("com.lc.app.demo.User");
3.1.2、获取类的相关类型
//获取类的修饰符
aClass.getModifiers();
//获取类的包名
aClass.getPackage();
//获取全类名
aClass.getName();
//获取父类
aClass.getSuperclass();
//获取类加载器
aClass.getClassLoader();
//获取简单类名
aClass.getSimpleName();
//获取类型实现的所有接口
aClass.getInterfaces();
//获取注解信息
aClass.getAnnotations();
3.1.3、字段的操作
public static void main(String[] args) throws Exception {
Class<User> userClass = User.class;
//获取User对象
User user = userClass.newInstance();
//获取当前类及其父类的的公有字段
Field[] fields = userClass.getFields();
//获取当前类的所有字段
Field[] declaredFields = userClass.getDeclaredFields();
//获取指定属性
Field userNameField = userClass.getDeclaredField("userName");
//放开操作私有属性的权限
userNameField.setAccessible(true);
//赋予属性数值
userNameField.set(user,"喵喵");
//获取指定静态属性
Field addressField = userClass.getDeclaredField("address");
//赋予静态变量数值,无需指定具体类
addressField.set(null,"地球村");
}
public class User {
private String userName;
public Integer age;
public static String address;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
3.1.4、方法的操作
public static void main(String[] args) throws Exception {
Class<User> userClass = User.class;
//获取User对象
User user = userClass.newInstance();
//获取当前类以及其父类的公有方法
userClass.getMethods();
//获取当前类的全部方法
userClass.getDeclaredMethods();
//获取指定方法
Method sayHello = userClass.getDeclaredMethod("sayHello");
//放开私有方法调用
sayHello.setAccessible(true);
//调用方法
sayHello.invoke(user);
//获取指定静态方法
Method say = userClass.getDeclaredMethod("say", String.class);
//调用方法
say.invoke(null,"hi 喵");
}
public class User {
public static void say(String msg) {
System.out.println(msg);
}
private static void sayHello() {
System.out.println("hello");
}
}
3.1.5、构造器的操作
public static void main(String[] args) throws Exception {
Class<User> userClass = User.class;
//获取当前类及其父类的公有方法
Constructor<?>[] constructors = userClass.getConstructors();
//获取当前类的所有方法
Constructor<?>[] declaredConstructors = userClass.getDeclaredConstructors();
//调用无参构造器
User user = userClass.newInstance();
//获取私有构造器
Constructor<User> declaredConstructor = userClass.getDeclaredConstructor(String.class, Integer.class);
//允许私有构造器调用
declaredConstructor.setAccessible(true);
//调用私有构造器
declaredConstructor.newInstance("喵喵", 18);
}
public class User {
private String userName;
private Integer age;
public User() {
}
private User(String userName, Integer age) {
this.userName = userName;
this.age = age;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
3.2、反射对单例的破坏
静态内部类单例代码:
public class InnerSingleton {
private InnerSingleton(){}
public static final InnerSingleton getInstance(){
return InnerHolder.SINGLETON;
}
private static class InnerHolder{
private static final InnerSingleton SINGLETON = new InnerSingleton();
}
}
反射调用与正常调用:
public static void main(String[] args) throws Exception {
InnerSingleton instance1 = InnerSingleton.getInstance();
InnerSingleton instance2 = InnerSingleton.getInstance();
System.out.println(instance1);
System.out.println(instance2);
Constructor<InnerSingleton> declaredConstructor = InnerSingleton.class.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
System.out.println(declaredConstructor.newInstance());
}
结果可见反射将单例破坏。
如果不希望反射被单例破坏,需要禁止在已经存在一个实例对象的情况下调用单例方法
public class InnerSingleton {
private InnerSingleton(){
if(InnerHolder.SINGLETON != null){
throw new RuntimeException("error");
}
}
public static final InnerSingleton getInstance(){
return InnerHolder.SINGLETON;
}
private static class InnerHolder{
private static final InnerSingleton SINGLETON = new InnerSingleton();
}
}
以上是关于Java核心知识反射的主要内容,如果未能解决你的问题,请参考以下文章