首页 > 编程语言 >十、耕耘Java(反射)

十、耕耘Java(反射)

时间:2024-09-17 13:51:27浏览次数:3  
标签:反射 Java 耕耘 System Class public println class out

十.耕耘Java(反射)

1.概念:

程序在运行过程中,

1.对于给定的一个类(Class)对象。可以获取到这个类(Class)对象的所有的属性和方法

2.对于给定的一个对象(new XXXClassName<? extend object>),都能够动态类的调用它任意一个属性和方法的机制,就叫做Java的反射机制。

反射的优缺点:

优点:

1.增加程序的灵活性

2.代码简洁,可读性强,可提高代码的复用率

缺点:

1.相较于直接调用在量大的情况下反射性能下降厉害

2.内部暴露和安全隐患

  1. class的组成在这里插入图片描述

二。基本操作

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

相关文章

  • 深度探索 Java 代码审计:筑牢安全防线的关键之路
    在当今高度数字化的时代,软件安全成为了至关重要的议题。对于众多使用Java语言进行开发的程序员而言,深入掌握Java代码审计技能,无疑是守护软件安全的核心手段。本文将围绕一本涵盖Java代码审计丰富知识的书籍目录,全面剖析Java代码审计的各个关键环节以及其在CTFAWD比......
  • Js高级总结1 JavaScript数据类型
    文章目录数据类型判断引用变量赋值问题js引擎如何管理内存对象函数生命周期回调函数前端立即执行函数(IIFE)闭包函数中的this数据类型1.1基本数据类型string:任意字符串number:任意数字null:nullboolean:true/falseundefined:undefined1.2对象类型object:任意对......
  • 毕业设计计算机选题推荐-基于Java的猫咖服务管理小程序
    精彩专栏推荐订阅:在下方专栏......
  • JAVA 基础知识点(一)
    摘要:本文所介绍知识点去粗取精,有助记忆。1.1 关键词定义:关键词是指被Java语言赋予特殊含义的单词。关键词特点:(1)关键词的字母全部小写;           (2) 代码编辑器对关键词都有高亮显示;如public,class,static。packagecom.itheima.test;importj......
  • 基于Java+SpringBoot+Mysql宠物领养系统功能设计与实现七
    一、前言介绍:1.1项目摘要随着社会的发展和人们生活水平的提高,宠物已经成为越来越多家庭的重要成员。宠物行业的快速发展,不仅体现在宠物数量的增加,还体现在宠物相关服务的不断完善和多样化。随着人们对宠物的喜爱程度加深,越来越多的人选择通过领养而非购买的方式获得宠物......
  • 基于Java+SpringBoot+Mysql宠物领养系统功能设计与实现八
    一、前言介绍:1.1项目摘要随着社会的发展和人们生活水平的提高,宠物已经成为越来越多家庭的重要成员。宠物行业的快速发展,不仅体现在宠物数量的增加,还体现在宠物相关服务的不断完善和多样化。随着人们对宠物的喜爱程度加深,越来越多的人选择通过领养而非购买的方式获得宠物......
  • 【JavaEE】——线程的诞生(超详细、易理解)
    一:进程对内存的管理1:进程的独立性:进程是如何管理内存的,核心:每个进程都有一块独立的内存,进程与进程之间的内存互不干扰,通常情况下,进程A的内存不能访问进程B的内存好处“进程独立性”:如果进程A的内存超出了给分配的内存大小(即内存越界)或者出现某些bug导致进程A挂掉,不会影响到......
  • 这段HTML、CSS和JavaScript代码构成了一个简单的网页游戏,名为“Catch The Insect”
    这段HTML、CSS和JavaScript代码构成了一个简单的网页游戏,名为“CatchTheInsect”。以下是对代码的详细分析和说明:HTML部分基础结构:使用<!DOCTYPEhtml>声明文档类型,确保浏览器以标准模式渲染页面。<htmllang="en">标签定义了文档的语言为英语。<head>部分包含了字符集......
  • ChatGPT中Java相关问答(包括Java基础知识和一些面试题)
    分享一个自己学习Java时的记录ChatGPT中的对话:ChatGPT链接包括如下问题HowtolearnJavainordertobecomeasoftwaredevelopmentengineer,pleasegivedetailsofthestudyprogramaswellasthereferencestudymaterials.详细解释java中的this引用解释一下类、......
  • java获取object中的value
    摘要: 本文主要探讨在Java编程环境中从Object对象中获取值(value)的不同方法。在Java中,Object是所有类的父类,经常会遇到需要从各种类型的对象中提取特定数据值的情况。通过对不同数据结构和对象类型的分析,阐述如何有效地获取其中包含的关键信息。一、引言在Java开发过程中,经......