2024 java 基础篇面试题

目录

基础篇 

一、Get 和 Post 的区别 

二、Java 多态的具体体现 

三、StringBuffer StringBuilder String 区别 

四、==和 equals 区别 

五、重写 equals 需要重写 hashCode 吗 

六、java 的基本数据类型 

七、List, Set, Collection, Collections 

八、ArrayList 和 LinedList 区别 

九、HashMap 和 Hashtable 区别 

十、Forword(请求转发) 与 Redirect (重定向) 

十一、switch 默认接受的几种数据类型 

十二、冒泡排序 

十三、 二分查找法 

十四、快速排序 

十五、阶乘(递归) 

十六、java Exception 体系结构 

十七、怎们定义异常规范的? 

十八、throw 和 throws 的区别 

十九、static 关键字理解 

二十、自动装箱 自动拆箱 

二十一、 final, finally, finalize 三者区别 

二十二、设计模式 

一.单例设计模式 

二.代理设计模式 

三.工厂设计模式 

四.适配器模式 

二十三、抽象类与接口的区别 

二十四、修饰符的作用 

二十五、this 和 super 关键字的作用和区别 

二十六、Servlet 生命周期及具体实现的三个方法 

二十七、反射的作用和原理 

二十八、泛型的概述 


基础篇 

一、Get Post 的区别 

1. get 是从服务器上获取数据,post 是向服务器传送数据。

2. get 传送的数据量较小,不能大于 2KB,post 传送的数据量较大,一般被默认为不受限制。

3.get 安全性非常低,post 安全性较高。但是执行效率却比 Post 方法好。

4.在进行文件上传时只能使用 post 而不能是 get。

二、Java 多态的具体体现 

1.面向对象编程有四个特征:抽象,封装,继承,多态。

2.多态有四种体现形式:接口和接口的继承,类和类的继承,重载,重写

3.其中重载和重写为核心。

重载(Overload) :重载发生在同一个类中,在该类中如果存在多个同名方法,但是方法的参数类型,个数,顺序不一样,那么说明该方法被重载了。

重写(Override):重写发生在子类继承父类的关系中,父类中的方法被子类继承,方法名,返回值类型,参数完全一样,但是方法体不一样,那么说明父类中的该方法被子类重写了

三、StringBuffer StringBuilder String 区别 

1. StringBuilder 执行效率高于 StringBuffer 高于 String.

2. String 是一个常量,是不可变的,所以对于每一次+=赋值 都会创建一个新的对象, StringBuffer 和 StringBuilder 都是可变的,当进行字符串拼接时采用 append 方法,在原来的基础上进行加,所以性能比 String 要高,又因为 StringBuffer 是线程安全的而 StringBuilder 是线程非安全的,所以 StringBuilder 的效率高于 StringBuffer。

3.对于大数据量的字符串的拼接,采用 StringBuffer, StringBuilder。

4.原理:

①String 类不可变,内部维护的 char[]数组长度不可变,为 final 修饰,String 类也是 final 修饰,不存在扩容。字符串拼接,截取,都会生成一个新的对象。频繁操作字 符串效率低下,因为每次都会生成新的对象。

②StringBuilder 类内部维护可变长度 char[],初始化数组容量为 16,存在扩容,其 append 拼接字符串方法内部调用 System 的 native 方法,进行数组的拷贝,不会重新生成新的 StringBuilder 对象。非线程安全的字符串操作类,其每次调用 toString 方法而重新生成的 String 对象,不会共享 StringBuilder 对象内部的 char[],而是会进行一次 char[]的 copy 操作。

四、==equals 区别 

1.==:在比较基本数据类型的时候,比较的是数据的值:比较引用数据类型时,比较的是地址值。

2.equals 方法在重写之前,比较的是俩个对象的地址值;在重写之后.比较的是属性值

五、重写 equals 需要重写 hashCode 吗 

需要。好比咱们有两个相同值的 User 对象,假如只重写 equals 而不重写 hashcode,那么User 类的 hashcode 方法就是 Object 默认的 hashcode 方法,由于默认的 hashcode 方法是根据对象的内存地址经哈希算法得来的,那么两者的 hashcode 不一定相等。

六、java 的基本数据类型 

数据类型 位 大小

byte (字节) l (8 位)

shot (短整型) 2(16 位)

int (整型) 4 (32 位)

long(长整型) 8(32 位)

float(浮点型) 4 (32 位)

double (双精度) 8 (64 位)

char (字符型) 2 (16 位)

boolean (布尔型) |

附加:

String 是基本数据类型吗? (String 不是基本数据类型)

String 的长度是多少,有限制? (长度受内存大小的影响)

七、List, Set, Collection, Collections 

1. List 和 Set 都是接口,他们都继承于接口 Collection, List 是一个有序的可重复的集台,而 Set 的无序的不可重复的集合。Collection 是集合的顶层接口,Collections 是一个封装了众多关于集合操作的静态方法的工具类,因为构造方法是私有的,所以不能实例化。

2, List 接口实现类有 ArrayList, LinkedList, Vector. ArrayList 和 Vector 是基于数组实现的,所以查询的时候速度快,而在进行增加和删除的时候速度较慢 LinkedList 是基于链式存储结构,所以在进行查询的时候速度较慢但在进行增加和删除的时候速度较快。又因为 Vector 是线程安全的,所以他和 ArrayList 相比而言,查询效率要低。

八、ArrayList LinedList 区别 

1. ArrayList 是 List 的一个实现类,他的查询修改效率比较快,因为顺序存储直接通过下标计算位置定位到需要获取的值,寻址次数较少.他的增加删除比较慢,每当增加或删除元素都需要移动后面所有元素所以效率比较低. LinkedLit 是 List 的一个实现类,他的增删效率比较高,因为他是节点存储,链式实现,每个节点都记录了上一个节点和下一个节点的地址, 针对于增加或修改只需要修改前后节点就可以,所以效率比较高.

2. ArrayList 实现原理 

ArrayList 实例都有一个容量,该容量是指用来存储列表元素的数组的大小。随着向ArrayList 中不断添加元素,其容量也自动增长。自动增长会带来数据向新数组的重新拷贝,它的一 个扩容是在原来基础上扩大 1.5 倍[intnewCapacity = oldCapacity +(ol dCapacity >> 1)] 确定之后就是把老数组 copy 到新数组中.如果可预知数据量的多少,可在构造 ArrayList 时指定其容量.

3. LinkedList 实现原理

LinkedList 数据存储是基于双向链表实现的. LinkedList 类中有一个内部私有类 Node,这个类就代表双端链表的节点 Node。这个类有三个属性,分别是前驱节点,本节点的值,后继节点。每个节点有两个 reference 指向前驱节点和后继节点。对于 LinkedList 来说提供了很多操作头尾节点的方法,例linkFirst linkLast 方法,拿 linkFirst 举例方法中首先用变量 f 来临时保存原有的 first 节点,然后调用的 node 的构造函数新建一个值为 e 的新节点,这个节点插入之后将作为 first 节点,所以新节点的前驱节点为null,值为 e,后继节点是 f,也就是未插入前的 first 节点。然后进行了判断如果 f==null,那就说明插入之前,链表是空的,那么新插入的节点不仅是 first 节点还是 last 节点,所以我们要更新 last 节点的状态,也就是 last 现在要指向新插入 的 newNode。如果 f!=null 那么就说明 last 节点不变,但是要更新 f 的前驱节点为 newNode, 最后 size 加一就完成了操作。

九、HashMap Hashtable 区别 

1. HashMap 和 Hashtable 都是用于存储键和值的对应关系,都是 Map 的实现类,都是使用哈希表的方式存储

2. Hashtable 是线程安全,HashMap 是线程不安全的

3. Hashtable 不能存储 null 键和 null 值,HashMap 可以存储 null 键和 null 值。

HashMap 实现原理

①当创建 HashMap 时,有一个默认的负载因子(load factor),其默认值为 0. 75,这是时间和空间成本上一种折衷:增大负载因子可以减少 Hash 表(就是那个 Entry 数组)所占用的内存空间,但会增加查询数据的时间开销,而查询是最频繁的的操作(HashMap 的 get()与 put() 方法都要用到查询) ;减小负载因子会提高数据查询的性能,但会增加 Hash 表所占用的内存空间。

HashMap 通过键的 hashCode 来快速的存取元素。当不同的对象发生碰撞时,HashMap通过单链表来解决,将新元素加入链表表头,通过 next 指向原有的元素。单链表在 Java 中的实现就是对象的引用(复合)。

Hash 冲突会造成 HashMap 的查询效率低下?

HashMap 里面没有出现 hash 冲突时,没有形成单链表时,hashmap 查找元素很快,get()方法能够直接定位到元素,但是出现单链表后,单个 bucket 里存储的不是一个 Entry, 而是一Entry链,系统只能必须按顺序遍历每个 Entry, 直到找到想搜索的 Entry 为止,如果恰好要搜索Entry 位于该Entry 链的最末端(该 Entry 是最早放入该 bucket 中),那系统必须循环到最后才能找到该元素。

ConcurrentHashMap

ConcurrentHashMap 并没有直接实现 map 接口,而是实现 ConCurrentMap 接口,ConCurrentMap 继承于 map 接口。

1) currentHashMap 使用分段锁的概念,它只会锁操作的那一段数据而不是整个Map 都上锁。

2) CorncrentHashMap 有很好的扩展性,在多线程环境下性能方面比做了同步的HashMap 要好,做了同步的 HashMap 和 Hashtable 在并发效率上区别不大,但是在单线程下 HashMap 的效率高于 ConcurrentHashMapConcurrentHashMap 实现原理 一个 ConcurrentHashMap 由多个 segment 组成,每一个 segment 都包含了一个 HashEntry数组的 hashtable,每一个 segment 包含子对自己的 hashtable 的操作,比如 get, put, replace 等操作,这些操作发生的时候,对自己的 hashtable 进行锁定。由于每一个 segment 写操作只锁定自己的 hashtable,所以可能存在多个线程同时写的情况,性能无疑好于只有一个hashtable 锁定的情况。Segment 继 承 了 ReentranLock. 所 以 它 就 是 一 种 可 重 入 锁 (RentrantLock). 在ConcurrentlashMap,一个 Segment 就是一个子哈希表,Segment 里维护了一个 hashEntry 数组,并发环境下,对于不同 Segment 的数据进行操作是不用考虑锁竞争的。在 JDK1.8 又将可重入锁修改成了 cas+synchronize 来实现,对于操作同段 map 的时候。进行竞争同一个锁的概率非常小,分段锁反而会造成更新等操作的长时间等待,使用cas+synchronize 可以将锁的粒度缩小。首先通过 hash 找到对应链表过后,查看是否是第一个object,如果是直接用 cas 原则插入无需加锁,如果不是链表第一个 object,则直接用链表第一 个 object 加锁。

十、Forword(请求转发) Redirect (重定向

1.Forword 是一个请求的延续,可以共享 request 的数据

2. Redirect 开启一个新的请求,不可以共享 request 的数据

3. Forword 转发地址栏不发生变化,Redirect 转发地址栏发生变化

十一、switch 默认接受的几种数据类型 

short, int, byte, char, Enum,String (jdk 版本 1.7 以上)

十二、冒泡排序 

算法思想

基本思想是对所有相邻记录的关键字值进行比效,如果是逆顺(a[j]>a[j+1]),则将其交换,最终达到有序化

public static void main(String[] args) {

    int[] arr = {25,13,335,6,23};

    System.out.println(Arrays.toString(bubbleSort(arr)));

}

private static int[] bubbleSort(int[] nums) {

    int len = nums.length;

    if (len == 0 || len== 1){

        return nums;

    }

    for (int i = 0; i < len - 1; i++) {

        for (int j = 0; j < len - 1 - i; j++) {

            if (nums[j + 1] < nums[j]) {

                int tmp = nums[j + 1];
                nums[j + 1] = nums[j];
                nums[j] = tmp;

            }

        }

    }

    return nums;

}

十三、 二分查找法 

前提条件:

1.存储在数组中(例如一维数组)

2.数组元素为有序

算法思想:

1. 搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程 结束;

2. 如果某---特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较

3. 如果在某一步骤数组为空,则代表找不到.

4. 代码示例

 public static void main(String[] args) {
        int[] arr = {1,2,3,4,5};
        int key = 5;

        System.out.println(commonBinarySearch(arr,key));
    }


public static int commonBinarySearch(int[] arr, int key) {
        int low = 0;
        int high = arr.length - 1;

        if (key < arr[low] || key > arr[high] || low > high) {
            return -1;
        }

        while (low <= high) {
            int middle = (low + high) / 2;

            if (arr[middle] > key) {
                high = middle - 1;
            } else if (arr[middle] < key) {
                low = middle + 1;
            } else {
                return middle;
            }
        }

        return -1;
    }

十四、快速排序 

/**

* @param num 排序的数组

* eparam left 数组开始下标值

* @param right 数组结束下标值

*/

 private static void quickSort(int[] num, int left, int right) {
        // 如果left等于right,即数组只剩一个元素,直接返回
        if (left >= right) {
            return ;
        }

        // 将最左边的元素设为基准值(pivot)
        int key = num[left];

        // 初始化两个指针i和j分别指向数组左右两端
        int i = left;
        int j = right;

        while (i < j) {
            // j向左移动,直到找到一个小于key的值(从右向左比较)
            while (num[j] >= key && i < j) {
                j--;
            }

            // 交换i位置与当前j位置的元素
            num[i] = num[j];

            // i向右移动,直到找到一个大于或等于key的值(从左向右比较)
            while (num[i] <= key && i < j) {
                i++;
            }

            // 交换i位置与当前j位置的元素
            num[j] = num[i];

            /**
             * 此时第一次循环比较结束,基准值(key)的位置已经确定。
             * 左边的值都小于基准值,右边的值都大于基准值,
             * 虽然两边的顺序可能还不完全有序,但接下来进行递归调用即可解决。
             */

            // 将基准值放到正确的位置
            num[i] = key;

            // 对左半部分数组进行递归排序
            quickSort(num, left, i - 1);

            // 对右半部分数组进行递归排序
            quickSort(num, i + 1, right);
        }
    }

十五、阶乘(递归

前提条件

1、有反复执行的过程(调用自身)

2、有跳出反复执行过程的条件(递归出口)

算法思想

1.程序调用自身的编程程技巧(自己调用自己)

代码示例

public class FactorialCalculator {
    // 定义计算阶乘的方法
    public static int multiply(int num) {
        if (num < 0) {
            System.out.println("请输入大于 0 的数!");
            return -1; // 返回错误码,表示输入无效
        } else if (num == 0 || num == 1) {
            return 1; // 阶乘的基本情况:0! = 1, 1! = 1
        } else {
            return multiply(num - 1) * num; // 递归调用,计算 num-1 的阶乘然后乘以 num
        }
    }

    // 主方法用于测试
    public static void main(String[] args) {
        int numberToFactorial = 10;
        int result = multiply(numberToFactorial);
        if (result != -1) {
            System.out.println(result); // 输出阶乘结果
        }
    }
}

十六、java Exception 体系结构 

1.体系图

(1) Throwable

①Error 错误

②Exception 异常

1) RuntimeException 运行时异常

I0Exception、FileNotFoundException、SQLException

2.在 Java 的异常体系里有一个所有异常和错误的超类 Throwable ,这个超类有两个直接子

类,一个表示错误的子类 error,另一个表示异常的子类 Exception。其中这个异常类 Exception

又分为运行时异常 RuntimeException 和非运行时异常 I0Exception,在运行时异常里都是

RuntimeException 类及其子类异常,例如空指针异常 NullPointException,下表越界异常

IndexOutBoundsException, 未找到类异常 ClassNotFoundException 异常,未知类型异常

UnknowTypeException,这些异常都是不检查异常,程序可以选择捕获处理,也可以不处理。

往往这些异常是程序逻辑错误引起的,所以应该尽可能避免这类异常的发生;还有那个错误

子 类 Error, Error 是 程 序 无 法 处 理 的 错 误 , 它 是 由 JVM 产 生 和 抛 出 的 , 比 如 OutOfMemoryError、ThreadDeath 等等。

十七、怎们定义异常规范的

1.尽量避免大段代码进行 try-catch, catch 时分清稳定代码和非稳定代码,对非稳定代码的 catch 尽可能的进行区分异常类型.也可以进行自定义异常,对异常进行统一封装,让整个项

目的异常处理更规范统一,同时使日志记录更加清晰,便于排查问题。

十八、throw throws 的区别 

1. throw 是对异常对象的抛出, throws 是对异常类型的声明,一旦用了 throw 关键字,就一定有一个异常对象出现;

2. throws 是对可能出现的异常类型的声明,即使声明了一些异常类型,在这个方法中,也可以不出现任何异常

3. throw 后面只能跟一个异常对象, throws 可以跟很多个异常类型

十九、static 关键字理解 

1. static 可以修饰变量,修饰方法,修饰代码块, static 修饰后是属于类的,所以只加载一 次他们的加载时机是随着类的加载而加载进入方法区,内存只中分配一块区域供所有类使

用,可以节省空间。

二十、自动装箱 自动拆箱 

1.自动装箱和拆箱(在 jdk1. 5 之后)

自动装箱:可以直接使用基本类型的数据,给引用类型变量赋值

自动拆箱:可以直接使用包装类对象,给基本类型变量赋值

二十一、 final, finally, finalize 三者区别 

1.final 是一个修饰符:

当 final 修饰一个变量的时候,变量变成一个常量,它不能被二次赋值

当 final 修饰方法时,该方法不能被重写

当 final 修饰类时,该类不能被继承

2.Finally :

Finally 只能与 try/catch 语句结合使用,finally 语句块中的语句一定会执行,并且会在 return, continue,break 关键字之前执行

3.finalize:

Finalize 是一个方法,属于 java.lang.0bject 类,finalize()方法是 GC (garbage collector 垃圾回收)运行机制的一部分,finalize()方法是在 GC 清理它所属的对象时被调用的。

二十二、设计模式 

.单例设计模式 

单例就是该类只能返回一一个实例。

单例所具备的特点:

1.私有化的构造函数

2.私有的静态的全局变量

3.公有的静态的方法

单例分为懒汉式、饿汉式和双重判定锁

饿汉式:

public class Singleton1 {

private Singleton1() {};

private static Singleton1 single = new Singleton1();

public static Singleton1 getInstance() {

return single;

}

}

懒汉式:

public class Singleton2private Singleton2() {}

private static Singleton2 single=null;

public static Singleton2 getInstance() {

if (single == null) {

single = new Singleton2() ;

}

return single;

}

}

线程安全:(双重判定锁)

public class Singleton3 {

private Singleton3() {}

private static Singleton3 single

publice static singleton3 getInstance(){

if(null == single) {

synchronized(single ){

if(null == single) {

single = new Singleton3();

}

}

}

return single;

}

}

.代理设计模式 

代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对

代理设计模式所具备的特点

1.抽象角色

2.真实角色

3.代理角色

代码示例

public interface TeacherService{

void teach();

}

接口的真实实现:真实角色

public class TeacherServiceImp1 imp1 ements TeacherService{

@Override

public void teach(){

System.out.print1n(”教学方法”);}

}

接口的代理实现:

private TeacherServiceImpl t = new TeacherServiceImp1();

@Override

public void teach(){

System.out.println("开启事物");

//执行逻辑代码

t.teach() ;

System.out.print1n("提交事物");

}

测试

@Test

public void test(){

TeacherService t = new StaticProxy() ;

t.teach() ;

}

.工厂设计模式 

工厂设计模式中,我们在创建对象时,不会对客户端暴露创建对象的逻辑

//接口类

public interfaceShape f

void draw();

//实现类 1

public class Rectangle implements Shape{

@Override

public void draw(){

System. out. print1n(Inside Rctangte:draw0) method.);

}

}

//实现类 2

public class Square eimplements Shape l

@Override

public void draw(){

System. out. println(" Inside Square::draw(0 method.");

}

}

//创建工厂类

public class ShapeFactory{

//使用 getShape 方法获取形状类型的对象

public Shape getShape(String shapeType){

if (shapeType == null){

return null;}

if (shapeType equalsIgnoreCase("CIRCLE")){

return new Circle() ;

}else if (shapeType.equalsIgnoreCase"RECTANGLE")){

return new Rectangle();

}else if (shapeType.equalsIgnoreCase("SQUARE")){

return new Square();

}

return null;

}

}

//测试

public static void main(String[] args) (

ShapeFactory shapeFactory = new ShapeFactory();

//获取 Rectangle 的对象,并调用它的 draw 方法

Shape shape2 = shapeFactory.getShape("RECTANGLE");

shape2. draw() ;

//获取 Square 的对象,并调用它的 drawep 方法

Shape shape3 = shapeFactory.getShape("SQUARE");

shape3. draw () ;

}

.适配器模式 

适配器模式解决接口与接口实现类之间继承矛盾问题(在编程实现里面:当一个接口实

现另一个接口的时候,有义务把接口中的方法都实现)

特征:

使用抽象类分离了接口与接口实现

抽象类分摊接口中的方法

使得接口可以随意的选择接口中的的方法米实现

代码示例

创建一个学生守则接口;

public interface 学生守则接口{

public void 考试后家长签字();

public void 每周免费看一次电影();

}

创建-个零食商贩(小学生干爹)

public abstract class 零食小商贩 implements 学生守则接口{

@Override

public void 考试后家长签字(){

System.out.println("家长签字”);

}

}创建一个小学类

public class 小学生 extends 零食小商贩{

@Override

public void 每周去看一次电影(){

System.out.println("去看电影");

}

}

定义目标类,通过小学生类调用所需要的方法

public classTestMain {

public static void main(String[] args){

学生守则接口 target = new 小学生();

target.考试后家长签字();

target.每周免费看一次电影();

}

}

二十三、抽象类与接口的区别 

1.一个类只能进行单继承,但可以实现多个接口。

2.有抽象方法的类,一定是抽象类,但是抽象类里面不一定有抽象方法。

3.接口里面所有的方法的默认修饰符为 public abstract, 接口里的成员变量默认修饰符

为:static final

二十四、修饰符的作用 

private default protected public

同一个类中    可以   可以    可以   可以

同一个包的类中    可以   可以    可以

不同包的子类中    可以   可以

不同包的类中      可以

二十五、this super 关键字的作用和区别 

1.this 关键字表示本类当前对象的引用

(1)哪个对象调用 this 所在的方法,this 就表示哪个对象

2. super 关键字表示本类当前对象的父类引用

(1)哪个对象在调用 super 所在的方法,super 就表示哪个对象中的父类中的成员

3. this 访问成员时,既可以访问当前类也可以访问父类, super 只能访问父类

二十六、Servlet 生命周期及具体实现的三个方法 

  1. 实例化对象 init()方法
    1. 当请求第一次访问的时候进行实例化,就是这个服务器被第一次访问的时候在 servlet 初始化时调用 init 方法,而且只被调用一次
  2. 调用工作方法 service()方法
    1. 每次请求都会调用该方法,该方法进行获取用户请求方式,通过用户请求方式调用相对应的 doGet 或者是 doPost 方法
  3. 销毁 destory()方法
    1. 当容器检测到一个 Servlet 实例应该从服务中被移除的时候,容器就会调用实例的

destroy()方法

二十七、反射的作用和原理 

1.反射机制其实就是指程序在运行的时候能够获取自身的信息。如果知道一个类的名称或者它的一个实例对象,就能把这个类的所有方法和变量的信息(方法名,变量名,方法,修饰符,类型,方法参数等等所有信息)找出来。如果明确知道这个类里的某个方法名+参数个数类型,还能通过传递参数来运行那个类里的那个方法

2.当然,在平时的编程中,反射基本用不到,但是在编写框架的时候,反射用的就多了,比如咱们要使用某一个类进行操作,但是这个类是用户通过配置文件配置进来的,你需要先读配置文件,然后拿到这个类的全类名:比如 test. Person,然后在利用反射 API 来完成相应的操作。

二十八、泛型的概述 

JDK1.5 开始提供泛型的概念,泛型实质上就是使程序员定义安全的类型。在没有出

现泛型之前,java 也提供了对 Object 的引用任意化操作,这种任意化操作就是对 0bject

用进行向下转型及向上转型的操作,但某些强制类型转换的错误也许不会被编译器捕捉,而是在运行后出现异常,可见强制类型转换存在安全隐患。

咱们也可以自定义泛型类,在声明该类对象时可以根据不同的需求指定<T>真正的类型,然后再使用声明泛型类对象时设置的数据类型。

泛型擦除

Java 的泛型是伪泛型。为什么说 Java 的泛型是伪泛型呢,他只是在咱们编译的时候进行检测,那么咱们就可以借助反射 动态的去获取操作方法,实现泛型擦除

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值