十.耕耘Java(反射)
1.概念:
程序在运行过程中,
1.对于给定的一个类(Class)对象。可以获取到这个类(Class)对象的所有的属性和方法
2.对于给定的一个对象(new XXXClassName<? extend object>),都能够动态类的调用它任意一个属性和方法的机制,就叫做Java的反射机制。
反射的优缺点:
优点:
1.增加程序的灵活性
2.代码简洁,可读性强,可提高代码的复用率
缺点:
1.相较于直接调用在量大的情况下反射性能下降厉害
2.内部暴露和安全隐患
二。基本操作
1.获取class类
package com.wedu.reflection;
import static java.lang.Class.forName;
public class ReflectionDemo01 {
public static void main(String[] args) throws ClassNotFoundException {
//获取Person对应的Class对象
Class<Person> class1 = Person.class;
System.out.println(class1);
Class class2= Class.forName("com.wedu.reflection.Person");
System.out.println(class2);
//通过Person对象中的getClass方法获取
Person p = new Person();
Class<? extends Person>class3=p.getClass();
System.out.println(class3);
//系统提供的一些类型获取Class对象
Class<String> stringClass = String.class;
Class<Integer> integerClass = int.class;
Class<int[]> aClass = int[].class;
Class<double[]> aClass1 = double[].class;
System.out.println(stringClass);
System.out.println(integerClass);
System.out.println(aClass);
System.out.println(aClass1);
//获取包装类对应的Class对象
Class<Integer> integerClass1 = Integer.class;
Class<Integer> type = Integer.TYPE;
//获取void没有返回结果的Class类型
Class<Void> voidClass = Void.class;
Class<Void> type1 = Void.TYPE;
System.out.println(integerClass1);
System.out.println(type);
System.out.println(voidClass);
System.out.println(type1);
}
}
输出结果:
class com.wedu.reflection.Person
class com.wedu.reflection.Person
class com.wedu.reflection.Person
class java.lang.String
int
class [I
class [D
class java.lang.Integer
int
class java.lang.Void
void
2.class对象中的常用方法
getName
newInstancee()
getSuperclass()
getInterfaces()
package com.wedu.reflection;
import java.lang.reflect.Array;
public class ReflectionDemo02 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Class<Student> studentClass = Student.class;
System.out.println(studentClass.getName());
Student student = studentClass.newInstance();
System.out.println(student);
Class<? super Student> superclass = studentClass.getSuperclass();
System.out.println(superclass);
System.out.println(superclass.getSuperclass());
Class<?>[] interfaces = studentClass.getInterfaces();
System.out.println(Array.toString(interfaces));
}
}
3.获取属性
Field getField(String name)
返回一个 Field对象,它反映此表示的类或接口的指定公共成员字段 类对象。
Field[] getFields()
返回包含一个数组 Field对象反射由此表示的类或接口的所有可访问的公共字段 类对象。
Field getDeclaredField(String name)
返回一个 Field对象,它反映此表示的类或接口的指定已声明字段 类对象。
Field[] getDeclaredFields()
返回的数组 Field对象反映此表示的类或接口声明的所有字段 类对象
package com.wedu.reflection;
import java.lang.reflect.Field;
public class ReflectionDemo03 {
public static void main(String[] args) {
Class<Student> studentClass = Student.class;
//etFields()获取当前类型和父类中的所有的public权限的字段
Field[] fields = studentClass.getFields();
for(Field field : fields){
System.out.println(field.getName());
}
System.out.println("--------------------------");
Field[] declaredFields = studentClass.getDeclaredFields();
for(Field field:declaredFields){
System.out.println(field.getName());
}
}
}
针对属性的操作:
package com.wedu.reflection;
import java.lang.reflect.Field;
public class ReflectionDemo03 {
public static void main(String[] args) throws Exception{
Class<Student> studentClass = Student.class;
//获取Student对象
Student student = studentClass.newInstance();
student.gender = "男";
//通过类型获取gender属性
Field gender = studentClass.getDeclaredField("gender");
System.out.println(gender.getName());
//获取对应访问权限修饰符1表示public 2表示private 4表示 protected
System.out.println(gender.getModifiers());
//获取或设置属性信息
System.out.println(gender.get(student));
//修改属性值
gender.set(student,"女");
System.out.println(gender.get(student));
Field stuNum = studentClass.getDeclaredField("stuNum");
//在反射中不允许直接操作私有属性,如果操作,则需要放开权限
stuNum.setAccessible(true);
System.out.println(stuNum.get(student));
//修改私有属性
stuNum.set(student,10001);
System.out.println(stuNum.get(student));
//操作结束,关闭权限
stuNum.setAccessible(false);
}
}
2.获取方法
Method getDeclaredMethod(String name, 类<?>... parameterTypes)
//返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 类对象。
Method[] getDeclaredMethods()
//返回包含一个数组 方法对象反射的类或接口的所有声明的方法,通过此表示 类对象,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法。
getMethod (String name, 类<?>... parameterTypes)
返回一个 方法对象,它反映此表示的类或接口的指定公共成员方法 类对象。
[] getMethods()
返回包含一个数组 方法对象反射由此表示的类或接口的所有公共方法 类对象,包括那些由类或接口和那些从超类和超接口继承的声明。
package com.wedu.reflection;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
public class ReflectionDemo06 {
public static void main(String[] args) throws Exception {
//公有方法
Class<Student> studentClass = Student.class;
Method say =studentClass.getDeclaredMethod("say",String.class);
Student student = new Student();
Object obj = say.invoke(student, "bobo");
System.out.println(obj);
//私有方法
Method eat = studentClass.getDeclaredMethod("eat");
eat.setAccessible(true);//放开权限
Object obj1 = eat.invoke(student);
System.out.println(obj1);
eat.setAccessible(false);//收回权限
System.out.println(say.getReturnType());
System.out.println(eat.getReturnType());
Class<?>[] exceptionTypes = say.getExceptionTypes();
System.out.println(Array.toString(ExceptionTypes));
Parameter[] parameters = say.getParameters();
for(Parameter parameter : parameters){
System.out.println(parameter.getName()+" "+parameter.getModifiers()+" "+ parameter.toString());
}
}
}
3.获取构造方法
Constructor<T> getConstructor(类<?>... parameterTypes)
返回一个 Constructor对象,该对象反映 Constructor对象表示的类的指定的公共 类函数。
Constructor<?>[] getConstructors()
返回包含一个数组 Constructor对象反射由此表示的类的所有公共构造 类对象。
Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
返回一个 Constructor对象,该对象反映 Constructor对象表示的类或接口的指定 类函数。
Constructor<?>[] getDeclaredConstructors()
返回一个反映 Constructor对象表示的类声明的所有 Constructor对象的数组 类 。
package com.wedu.reflection;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.util.Arrays;
public class ReflectionDemo07 {
public static void main(String[] args) {
Class<Student> studentClass = Student.class;
//获取对应构造器getConstructors()获取当前类中的所有的构造器
Constructor<?>[] constructors = studentClass.getConstructors();
for(Constructor constructor:constructors){
System.out.println(constructor.getName()+" "+ Arrays.toString(constructor.getParameters()));
}
System.out.println("------------------------");
//获取当前类中的所有的构造方法包括private修饰的
Constructor<?>[] declaredConstructors = studentClass.getDeclaredConstructors();
for(Constructor constructor:declaredConstructors){
System.out.println(constructor.getName()+" "+ Arrays.toString(constructor.getParameters()));
}
}
}
Constructor操作
package com.wedu.reflection;
import java.lang.reflect.Constructor;
import java.util.Arrays;
public class ReflectionDemo08 {
public static void main(String[] args) throws Exception {
Class<Student> studentClass = Student.class;
Constructor<Student> c = studentClass.getDeclaredConstructor(Integer.class);
System.out.println(c.getName());
System.out.println(c.getModifiers());
System.out.println(c.getParameterCount());
//操作private修饰的构造方法同样需要放开权限
c.setAccessible(true);
//通过构造器创建实例对象
Student s = c.newInstance(1009);
//操作结束,关闭权限
c.setAccessible(false);
System.out.println(s);
//通过构造器显示抛出的异常
Class<?>[] exceptionTypes = c.getExceptionTypes();
System.out.println(Arrays.toString(exceptionTypes));
}
}
静态属性·和·静态方法操作
package com.wedu.reflection;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectionDemo09 {
public static void main(String[] args) throws Exception {
Class<Student> studentClass = Student.class;
//静态属性的操作
Field s1 = studentClass.getDeclaredField("s1");
System.out.println(s1.get("s1"));
s1.set(null,"hahaha");
System.out.println(s1.get("s1"));
//静态方法的调用
Method fun1 = studentClass.getDeclaredMethod("fun1");
fun1.invoke(null);
}
}
静态代码块
package com.wedu.reflection;
public class ReflectionDemo10 {
public static void main(String[] args) throws Exception{
//.class的方式是不会触发类加载的
Class<Student> studentClass = Student.class;
//Class.forName 会显示的加载类
Class<?> aClass = Class.forName("com.wedu.reflection.Student");
//对象.getClass()先要获取对象,肯定执行静态代码块
}
}
综合练习
package com.wedu.reflectionTest;
import java.io.File;
import java.lang.reflect.Constructor;
public class FileTest {
public static void main(String[] args) {
try {
// 1. 利用Class类的forName方法得到File类
Class<?> fileClass = Class.forName("java.io.File");
// 2. 在控制台打印File类的所有构造器
System.out.println("File class constructors:");
Constructor<?>[] constructors = fileClass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
// 3. 通过newInstance的方法创建File对象,并创建D:\mynew.txt文件
// 注意:newInstance方法在Java 9之后已被弃用,建议使用Constructor的newInstance方法
Constructor<?> fileConstructor = fileClass.getConstructor(String.class);
File file = (File) fileConstructor.newInstance("D:\\mynew.txt");
// 检查文件是否创建成功
if (file.createNewFile()) {
System.out.println("File created successfully: " + file.getAbsolutePath());
} else {
System.out.println("File already exists: " + file.getAbsolutePath());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
三.单例的漏洞
私有的构造器能够创建出多个实例对象
Bug还原
单例代码
package com.wedu.reflection;
public class SingletonTest {
//声明一个静态的单例属性
private static SingletonTest instance;
//私有化构造器
private SingletonTest() {
}
//对外提供一个静态的共有的方法来获取单例对象
public static SingletonTest getInstance() {
if(instance==null){
synchronized (SingletonTest.class){
if(instance == null){
instance = new SingletonTest();
}
}
}
return instance;
}
}
测试代码
package com.wedu.reflection.studeny;
import com.wedu.reflection.SingletonTest;
import java.lang.reflect.Constructor;
public class ReflectionDemo11 {
public static void main(String[] args) throws Exception{
SingletonTest i1 = SingletonTest.getInstance();
System.out.println(i1);
SingletonTest i2 = SingletonTest.getInstance();
System.out.println(i2);
//通过反射的方式来获取对象 获取私有的构造器
Constructor<SingletonTest> c = SingletonTest.class.getDeclaredConstructor();
c.setAccessible(true);
SingletonTest i3 = c.newInstance();
SingletonTest i4 = c.newInstance();
c.setAccessible(false);
System.out.println(i3);
System.out.println(i4);
}
}
输出结果;
com.wedu.reflection.SingletonTest@3feba861//正常获取
com.wedu.reflection.SingletonTest@3feba861//正常获取
com.wedu.reflection.SingletonTest@5b480cf9//反射获取
com.wedu.reflection.SingletonTest@6f496d9f//反射获取
造成Bug的原因:private的构造方法多次执行,
解决办法:在私有构造方法中添加逻辑
//私有化构造器
private SingletonTest() {
System.out.println("构造方法执行了。。。");
if(instance !=null) {
throw new RuntimeException("实例已经创建了,不允许再创建了。。。");
}
}
创建多个就会抛异常
案例:
:private的构造方法多次执行,
解决办法:在私有构造方法中添加逻辑
//私有化构造器
private SingletonTest() {
System.out.println("构造方法执行了。。。");
if(instance !=null) {
throw new RuntimeException("实例已经创建了,不允许再创建了。。。");
}
}
标签:反射,Java,耕耘,System,Class,public,println,class,out
From: https://blog.csdn.net/weixin_64846176/article/details/142314008