Java反射 Field类的使用全方位解析

Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。

Field 成员变量的介绍

每个成员变量有类型和值。

java.lang.reflect.Field 为我们提供了获取当前对象的成员变量的类型,和重新设值的方法。

获取变量的类型

类中的变量分为两种类型:基本类型和引用类型:

基本类型( 8 种)

整数:byte, short, int, long

浮点数:float, double

字符:char

布尔值:boolean

引用类型

所有的引用类型都继承自 java.lang.Object

类,枚举,数组,接口都是引用类型

java.io.Serializable 接口,基本类型的包装类(比如 java.lang.Double)也是引用类型

java.lang.reflect.Field 提供了两个方法获去变量的类型:

Field.getType():返回这个变量的类型

Field.getGenericType():如果当前属性有签名属性类型就返回,否则就返回 Field.getType()

Class<?> getType()
          返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型。
Type getGenericType()
          返回一个 Type 对象,它表示此 Field 对象所表示字段的声明类型。

实例:

测试类:

public class A
{
 public String id;
 protected String name;
 int age;
 private String sex;
 int[][] ints;
}

main方法:

public class Test
{
 /**
  * 返回该类所在包的包名字字符串
  * @param thisClass 一个类的Class对象
  * @return 该类的包名字字符串
  */
 public static String getThisPackageName(Class<?> thisClass)
 {
  String thisClassName=thisClass.getName();
  String thispackage=thisClassName.substring(0,thisClassName.lastIndexOf("."));
  return thispackage;
 }
 public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException
 {
  Class strClass=Class.forName(getThisPackageName(Test.class)+".A");
  //获取类的所有声明的字段
  Field[] sField=strClass.getDeclaredFields();
  for (Field field : sField)
  {
   //获取字段的名字
   System.out.printf("Field:%-4s|",field.getName());
   //获取字段的类型的Class类,然后获取规范化的名字
   System.out.printf("Type:%-18s|",field.getType().getCanonicalName());
   //获取字段的类型的Type类对象,然后获取类的名字
   System.out.printf("GenericType:%-18s|",field.getGenericType().getTypeName());
   System.out.println();
  }
 }
}

运行结果:

Field:id  |Type:java.lang.String  |GenericType:java.lang.String  |
Field:name|Type:java.lang.String  |GenericType:java.lang.String  |
Field:age |Type:int               |GenericType:int               |
Field:sex |Type:java.lang.String  |GenericType:java.lang.String  |
Field:ints|Type:int[][]           |GenericType:int[][]           |

可以看到这个两个方法都能正确的返回当前字段的类型。这两个方法的区别还是在返回类型上

getType()方法返回的是Class<?>类型的,而getGenericType()返回的是Type类型的。

获取成员变量的修饰符

成员变量可以被以下修饰符修饰:

访问权限控制符:public, protected, private

限制只能有一个实例的:static

不允许修改的:final

不会被序列化:transient

线程共享数据的一致性:volatile

注解

类似获取 Class 的修饰符,我们可以使用 Field.getModifiers() 方法获取当前成员变量的修饰符。

返回 java.lang.reflect.Modifier 中定义的整形值。然后使用 Modifier.toString(int mod)解码成字符串

实例:获取上面的A类的字段的类型和修饰符:

public static void printField(Class<?> class1)
{
 // 获取类的所有声明的字段
 Field[] sField = class1.getDeclaredFields();
 for (Field field : sField)
 {
  // 获取字段的名字
  System.out.printf("字段:%-4s|", field.getName());
  // 获取字段的类型的Class类,然后获取规范化的名字
  System.out.printf("类型:%-18s|",field.getGenericType().getTypeName());
  //使用Field.getModifiers(),可获取字段的修饰符编码,
  //然后再使用Modifier.toString(int code),来解码成字字符串
  System.out.printf("修饰符:%s", Modifier.toString(field.getModifiers()));
  System.out.println();
 }
}

main方法:

public static void main(String[] args) throws ClassNotFoundException,
        NoSuchFieldException, SecurityException
{
    Class AClass = Class.forName(getThisPackageName(Test.class) + ".A");
    printField(AClass);
}

运行结果:

字段:id  |类型:java.lang.String  |修饰符:public
字段:name|类型:java.lang.String  |修饰符:protected
字段:age |类型:int               |修饰符:
字段:sex |类型:java.lang.String  |修饰符:private
字段:ints|类型:int[][]           |修饰符:

由于 Field 间接继承了 java.lang.reflect.AnnotatedElement ,因此运行时也可以获得修饰成员变量的注解,当然前提是这个注解被 java.lang.annotation.RetentionPolicy.RUNTIME 修饰。

获取和修改成员变量的值

拿到一个对象后,我们可以在运行时修改它的成员变量的值,对运行时来说,反射修改变量值的操作和类中修改变量的结果是一样的。

1.基本类型的获取方法:

byte getByte(Object obj)
          获取一个静态或实例 byte 字段的值。
int getInt(Object obj)
          获取 int 类型或另一个通过扩展转换可以转换为 int 类型的基本类型的静态或实例字段的值。
 short getShort(Object obj)
          获取 short 类型或另一个通过扩展转换可以转换为 short 类型的基本类型的静态或实例字段的值。
 long getLong(Object obj)
          获取 long 类型或另一个通过扩展转换可以转换为 long 类型的基本类型的静态或实例字段的值。
 float getFloat(Object obj)
          获取 float 类型或另一个通过扩展转换可以转换为 float 类型的基本类型的静态或实例字段的值。
 double getDouble(Object obj)
          获取 double 类型或另一个通过扩展转换可以转换为 double 类型的基本类型的静态或实例字段的值。
 boolean getBoolean(Object obj)
          获取一个静态或实例 boolean 字段的值。
 char getChar(Object obj)
          获取 char 类型或另一个通过扩展转换可以转换为 char 类型的基本类型的静态或实例字段的值。

2.基本类型的setter方法:

 void setByte(Object obj, byte b)
          将字段的值设置为指定对象上的一个 byte 值。
 void setShort(Object obj, short s)
  将字段的值设置为指定对象上的一个 short 值。
 void setInt(Object obj, int i)
          将字段的值设置为指定对象上的一个 int 值。
 void setLong(Object obj, long l)
          将字段的值设置为指定对象上的一个 long 值。
 void setFloat(Object obj, float f)
          将字段的值设置为指定对象上的一个 float 值。
 void setDouble(Object obj, double d)
          将字段的值设置为指定对象上的一个 double 值。
 void setBoolean(Object obj, boolean z)
          将字段的值设置为指定对象上的一个 boolean 值。
 void setChar(Object obj, char c)
          将字段的值设置为指定对象上的一个 char 值。

3.引用类型的getters方法:

Object get(Object obj) 

返回指定对象上此 Field 表示的字段的值。

4.引用类型的setters方法:

void set(Object obj, Object value) 

将指定对象变量上此 Field 对象表示的字段设置为指定的新值。

实例:

(1)基本类型的获取和修改:

测试类:

public class C
{
 private int a;
 private double d;
 private boolean flag;
 @Override
 public String toString()
 {
  return "C [a=" + a + ", d=" + d + ", flag=" + flag + "]";
 }
 public C(int a, double d, boolean flag)
 {
  super();
  this.a = a;
  this.d = d;
  this.flag = flag;
 }
 public int getA()
 {
  return a;
 }
 public void setA(int a)
 {
  this.a = a;
 }
 public double getD()
 {
  return d;
 }
 public void setD(double d)
 {
  this.d = d;
 }
 public boolean isFlag()
 {
  return flag;
 }
 public void setFlag(boolean flag)
 {
  this.flag = flag;
 }

}

main方法类:

import java.lang.reflect.Field;
public class TestGetSetBase
{
 public static void main(String[] args)
   throws IllegalArgumentException, IllegalAccessException
 {

  C c = new C(10, 123.456, true);
  System.out.println("c对象的值:");
  System.out.println(c);
  System.out.println("-------------------------------");
  Class cClass = c.getClass();
  // 获取所有的字段
  Field[] cFields = cClass.getDeclaredFields();
  for (Field field : cFields)
  {
   field.setAccessible(true);
   System.out.println("获取到字段:" + field.getType().getCanonicalName()
     + ",值:" + field.get(c));
  }
  for (Field field : cFields)
  {
   if (field.getType().getCanonicalName() == "int")
   {
    field.setInt(c, 30);
   } else if (field.getType().getCanonicalName() == "double")
   {
    field.setDouble(c, 6789.9901);
   } else if (field.getType().getCanonicalName() == "boolean")
   {
    field.setBoolean(c, false);
   }
   // System.out.println(field.getType().getCanonicalName());
  }
  System.out.println("-------------------------------");
  System.out.println("现在的c对象的值:");
  System.out.println(c);
 }
}

运行结果:

c对象的值:
C [a=10, d=123.456, flag=true]
-------------------------------
获取到字段:int,值:10
获取到字段:double,值:123.456
获取到字段:boolean,值:true
-------------------------------
现在的c对象的值:
C [a=30, d=6789.9901, flag=false]
(2)引用类型的获取和修改

测试类:

public class B
{
 private String id;
 private String Name;
 public B(String id, String name)
 {
  super();
  this.id = id;
  Name = name;
 }
 public B(){}
 @Override
 public String toString()
 {
  return "B [id=" + id + ", Name=" + Name + "]";
 }
 public String getId()
 {
  return id;
 }
 public void setId(String id)
 {
  this.id = id;
 }
 public String getName()
 {
  return Name;
 }
 public void setName(String name)
 {
  Name = name;
 }
}

这里测试的类B的字段都是private类型的,在外部类是无法直接访问到这些成员属性的,想要获取和修改只能通过B类的getters和setters方法进行。使用反射我可以绕过这些限制,因为是私有类型的要使用 Field.setAccessible(true); 方法解除限制

main方法类:

import java.lang.reflect.Field;
public class TestGetSet
{
    public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException
    {
        B b=new B("B1000","小明");
        System.out.println("b对象的值:");
        System.out.println(b);
        System.out.println("---------------------------------");
        Class bClass=b.getClass();
        //获取共有的字段列表
        Field[] bFields=bClass.getDeclaredFields();
        System.out.println("通过反射获取字段的值:");
        //获取字段的值,Field.get(对象);
        for (Field field : bFields)
        {
            field.setAccessible(true);//获取权限
            //获取b对象的字段field里面的值
            System.out.println("字段:"+field.getType().getName()+",值:"+field.get(b));
        }
        //修改字段的值
        for (Field field : bFields)
        {
            field.set(b, "哈哈");
        }
        System.out.println("---------------------------------");
        System.out.println("现在的b对象的值:");
        System.out.println(b);
    }
}

运行结果:

b对象的值:
B [id=B1000, Name=小明]
---------------------------------
通过反射获取字段的值:
字段:java.lang.String,值:B1000
字段:java.lang.String,值:小明
---------------------------------
现在的b对象的值:
B [id=哈哈, Name=哈哈]

再说一下setAccessible()方法,Field的setAccessible()方法是从AccessibleObject类继承而来的。AccessibleObject 类是 Field、Method 和 Constructor 对象的基类。

它提供了在使用时 取消默认 Java 语言访问控制检查的能力。

一般情况下,我们并不能对类的私有字段进行操作,利用反射也不例外,但有的时候,例如要序列化的时候,我们又必须有能力去处理这些字段,这时候,我们就需要调用AccessibleObject上的setAccessible()方法来允许这种访问,而由于反射类中的Field,Method和Constructor继承自AccessibleObject,因此,通过在Field,Method和Constructor这些类上调用setAccessible()方法,我们可以操作这些字段无法访问的字段。

返回boolean的方法:

boolean equals(Object obj)
          将此 Field 与指定对象比较。
boolean isEnumConstant()
          如果此字段表示枚举类型的元素,则返回 true;否则返回 false。
boolean isSynthetic()
          如果此字段是复合字段,则返回 true;否则返回 false。

返回String的方法:

String getName()
         返回此 Field 对象表示的字段的名称。
String toGenericString()
         返回一个描述此 Field(包括其一般类型)的字符串。
String toString()
         返回一个描述此 Field 的字符串。 

其他方法:

1.equals()和hashCode()

int hashCode()
          返回该 Field 的哈希码。
boolean equals(Object obj)
          将此 Field 与指定对象比较。 

2.返回注释的方法:

<T extends Annotation> T  getAnnotation(Class<T> annotationClass)
          如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
Annotation[] getDeclaredAnnotations()
          返回直接存在于此元素上的所有注释。

3.返回字段所在的类或者接口的Class对象

 Class<?> getDeclaringClass()
          返回表示类或接口的 Class 对象,该类或接口声明由此 Field 对象表示的字段。

4.返回字段的类型(Type)

Type getGenericType()
          返回一个 Type 对象,它表示此 Field 对象所表示字段的声明类型。

5.返回修饰符编码:这个方法上面已经提到了,可以使用Modifier.toString(int mod)方法,把获取到的编码转换成修饰符字符串

 int getModifiers()
以整数形式返回由此 Field 对象表示的字段的 Java 语言修饰符。

常见错误 1 :无法转换类型导致的 java.lang.IllegalArgumentException

在使用反射获取或者修改一个变量的值时,编译器不会进行自动装/拆箱。所以我们无法给 Integer 类型的属性使用 setInt() 方法重新设值,必须给它赋一个 Integer 对象才可以。

否则会因为无法转换类型而出现java.lang.IllegalArgumentException

实例:

import java.lang.reflect.Field;
public class TestInterger
{
    private Integer integer;
    public TestInterger(Integer integer)
    {
        this.integer = integer;
    }
    public String toString()
    {
        return "TestInterger [integer=" + integer + "]";
    }
    public static void main(String[] args) throws NoSuchFieldException,
            SecurityException, IllegalArgumentException, IllegalAccessException
    {
        // 这里传入的30是int类型的,会自动装箱成Integer类型
        TestInterger testInterger = new TestInterger(30);
        System.out.println("testInteger对象:");
        System.out.println(testInterger);
        System.out.println("----------------------------------");
        Class thisClass = testInterger.getClass();
        // 获取integer字段
        Field inField = thisClass.getDeclaredField("integer");
        inField.setAccessible(true);// 不做访问控制检查
        // 获取字段的值
        System.out.println("成员属性:" + inField.getType().getCanonicalName()
                + ",值:" + inField.get(testInterger));
        // 修改成员属性integer:
        inField.setInt(testInterger, 90);
        System.out.println("----------------------------------");
        System.out.println(testInterger);
    }
}

运行结果:

testInteger对象:
TestInterger [integer=30]
----------------------------------
成员属性:java.lang.Integer,值:30
Exception in thread "main" java.lang.IllegalArgumentException:
Can not set java.lang.Integer field reflect.fieldtest.type.TestInterger.integer to (int)90
 at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(Unknown Source)
 at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(Unknown Source)
 at sun.reflect.UnsafeObjectFieldAccessorImpl.setInt(Unknown Source)
 at java.lang.reflect.Field.setInt(Unknown Source)
 at reflect.fieldtest.type.TestInterger.main(TestInterger.java:34)

解决方法:把上面的 inField.setInt(testInterger, 90);改成 inField.set(testInterger, 90);即可;

set方法原型:

Field.set(Objet obj2,Object obj2),这样我们传入90这个int类型的数据时,在编译阶段编译器会自动进行装箱等同于

inField.set(testInterger, new Integer(90))。这样运行时,获取到的是Integer类型的,能正常的传入。

这里再来说一下自动拆箱装箱的事情:

自动装箱是java编译器在java原生类型和对应的对象包装类型上做的自动转换。

例如,把int 装换成 Integer double转换成Double等等。

如果是反过来转换,那么叫做自动拆箱,也是编译器为我们做的事情。

强调:自动拆箱装箱发生在编译时刻,反射时发生在程序运行时刻。

为了不混淆,利用反射修改包装类的值的时候,使用set方法,并且尽量手动装箱,也就是写成下面的形式:

inField.set(testInterger, new Integer(90))

常见错误 2:反射非 public 的变量导致的 NoSuchFieldException

如果你使用 Class.getField() 或者 Class.getFields() 获取非 public 的变量,编译器会报 java.lang.NoSuchFieldException 错。

常见错误 3 :修改 final类型的变量导致的 IllegalAccessException

当你想要获取或者修改 不可修改(final)的变量时,会导致IllegalAccessException。

由于 Field 继承自 AccessibleObject , 我们可以使用 AccessibleObject.setAccessible() 方法告诉安全机制,这个变量可以访问。

也就是Field.setAccessible(true)。告诉安全机制当前的这字段不做访问权限检查,这样我们就能反射修改final修饰成常量了。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • java反射机制的一些学习心得小结

    概述 之前在了解Spring的类加载机制的时候,了解了java的反射机制.但是,我对反射理解一直不深.也一直有点疑惑:Spring为什么利用反射创建对象?直接new对象和依靠反射创建对象有什么区别?什么是动态加载类? 什么是反射? 要想知道反射到底是什么,首先需要知道java的类加载和对象创建的机制. 当我们写完一个java文件的时候,后缀是.java.在我们利用IDE执行java文件的时候,其实IDE也帮我们运行了javac,即java编译器.编译器会将.java文件编译成.class文件.j

  • Java中的注解和反射实例详解

    一.注解 注解(Annotation): 从jdk5.0开始引进,可以对程序进行解释或被其他程序读取. 注解格式:"@注释名",并可以添加一些参数. 例:@MyAnnotation(value='value') 1.内置注解 @override: 用于修饰方法,表示该方法声明是重写或实现一个父类的方法 @Deprecated: 用于修饰方法.属性.类,表示已过时不建议使用的 @SuppressWarnings: 用于抑制编译时的警告信息 2.元注解 作用:用于注解其他注解 @Targe

  • JAVA基础之注解与反射的使用方法和场景

    注解 注解定义 Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制. Java 语言中的类.方法.变量.参数和包等都可以被标注.和注释不同,Java 标注可以通过反射获取标注内容.在编译器生成类文件时,标注可以被嵌入到字节码中.Java 虚拟机可以保留标注内容,在运行 时可以获取到标注内容 . 当然它也支持自定义 Java 标注. 注解与注释的区别:注解是给机器看的注释,而注释是给程序员看的提示,编译时自动忽略注释. 使用场景 编译格式检查 反射中解

  • Java 使用反射调用jar包中的类方式

    下面讲展示的是从image.jar包中调用image.Buddy类的方法. public class Main { public static void main(String[] args) { try { // 两种方式都可以 URL url = new File("/Users/wuchen/Documents/IntelliJIDEA/Applet/out/production/Applet/image.jar").toURI().toURL(); // URL url = n

  • java 非常好用的反射框架Reflections介绍

    Reflections通过扫描classpath,索引元数据,并且允许在运行时查询这些元数据. 使用Reflections可以很轻松的获取以下元数据信息: 1)获取某个类型的所有子类:比如,有一个父类是TestInterface,可以获取到TestInterface的所有子类. 2)获取某个注解的所有类型/字段变量,支持注解参数匹配. 3)使用正则表达式获取所有匹配的资源文件 4)获取特定签名方法. 通常的用法有: 引入依赖jar <dependency> <groupId>org

  • Java反射框架Reflections示例详解

    MAVEN 坐标 <dependency> <groupId>org.reflections</groupId> <artifactId>reflections</artifactId> <version>0.9.10</version> </dependency> Reflections 的作用 Reflections通过扫描classpath,索引元数据,并且允许在运行时查询这些元数据. 获取某个类型的所有

  • java反射获取包下所有类的操作

    我就废话不多说了,大家还是直接看代码吧~ public static void main(String[] args) { try { // 获取包名下所有类 Set<Class<?>> classes = getClasses("com"); for(Class c:classes){ // 打印有RestController 的类 if(c.isAnnotationPresent(RestController.class)){ System.out.prin

  • Java反射 Field类的使用全方位解析

    Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限.反射的字段可能是一个类(静态)字段或实例字段. Field 成员变量的介绍 每个成员变量有类型和值. java.lang.reflect.Field 为我们提供了获取当前对象的成员变量的类型,和重新设值的方法. 获取变量的类型 类中的变量分为两种类型:基本类型和引用类型: 基本类型( 8 种) 整数:byte, short, int, long 浮点数:float, double 字符:char 布尔值:boolean 引用类

  • Java反射技术详解及实例解析

    前言 相信很多人都知道反射可以说是Java中最强大的技术了,它可以做的事情太多太多,很多优秀的开源框架都是通过反射完成的,比如最初的很多注解框架,后来因为java反射影响性能,所以被运行时注解APT替代了,java反射有个开源框架jOOR相信很多人都用过,不过我们还是要学习反射的基础语法,这样才能自己写出优秀的框架,当然这里所讲的反射技术,是学习Android插件化技术.Hook技术等必不可少的! 一.基本反射技术   1.1 根据一个字符串得到一个类 getClass方法 String nam

  • Java原子变量类原理及实例解析

    这篇文章主要介绍了Java原子变量类原理及实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.原子变量类简介 为何需要原子变量类 保证线程安全是 Java 并发编程必须要解决的重要问题.Java 从原子性.可见性.有序性这三大特性入手,确保多线程的数据一致性. 确保线程安全最常见的做法是利用锁机制(Lock.sychronized)来对共享数据做互斥同步,这样在同一个时刻,只有一个线程可以执行某个方法或者某个代码块,那么操作必然是原子性

  • Java 反射修改类的常量值、静态变量值、属性值实例详解

    前言 有的时候,我们需要修改一个变量的值,但变量也许存在于 Jar 包中或其他位置,导致我们不能从代码层面进行修改,于是我们就用到了下面的场景,通过反射来进行修改变量的值. 定义一个实体类 class Bean{ private static final Integer INT_VALUE = 100; } 利用反射修改私有静态常量方法 System.out.println(Bean.INT_VALUE); Field field = Bean.class.getField("INT_VALUE

  • Java反射(Class类,Class对象获取)

    目录 Java反射超详解 1.反射基础 1.1Class类 1.2类加载 2.反射的使用 2.1Class对象的获取 2.2Constructor类及其用法 2.3Field类及其用法 Java反射超详解 1.反射基础 Java反射机制是在程序的运行过程中,对于任何一个类,都能够知道它的所有属性和方法:对于任意一个对象,都能够知道它的任意属性和方法,这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制. Java反射机制主要提供以下这几个功能: 在运行时判断任意一个对象所属的类

  • Java使用Scanner类获取用户输入过程解析

    这篇文章主要介绍了Java使用Scanner类获取用户输入过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 创建 Scanner 对象的基本语法: Scanner s = new Scanner(System.in); Scanner 类的 next() 方法 import java.util.Scanner; class Test{ public static void main(String[] args){ String s; Sc

  • Java反射 PropertyDescriptor类案例详解

    JAVA中反射机制(JavaBean的内省与BeanUtils库) 内省(Introspector) 是Java 语言对JavaBean类属性.事件的一种缺省处理方法. JavaBean是一种特殊的类,主要用于传递数据信息,这种类中的方法主要用于访问私有的字段,且方法名符合某种命名规则.如果在两个模块之间传递信息,可以将信息封装进JavaBean中,这种对象称为"值对象"(Value Object),或"VO".方法比较少.这些信息储存在类的私有变量中,通过set(

  • Java 反射获取类详细信息的常用方法总结

    类ReflectionDemo 复制代码 代码如下: package Reflection; @Deprecated public class ReflectionDemo {     private String pri_field;     public String pub_field;     public ReflectionDemo(){}     public ReflectionDemo(String name){}     private ReflectionDemo(Stri

  • Java并发工具类LongAdder原理实例解析

    LongAdder实现原理图 高并发下N多线程同时去操作一个变量会造成大量线程CAS失败,然后处于自旋状态,导致严重浪费CPU资源,降低了并发性.既然AtomicLong性能问题是由于过多线程同时去竞争同一个变量的更新而降低的,那么如果把一个变量分解为多个变量,让同样多的线程去竞争多个资源. LongAdder则是内部维护一个Cells数组,每个Cell里面有一个初始值为0的long型变量,在同等并发量的情况下,争夺单个变量的线程会减少,这是变相的减少了争夺共享资源的并发量,另外多个线程在争夺同

  • Java中ArrayList类的源码解析

    前言:在前面我们提到数据结构的线性表.那么今天我们详细看下Java源码是如何实现线性表的,这一篇主要讲解顺序表ArrayList链式表下一篇在提及. 1:ArrayList结构图 2:关于Collection和List的区别 最好的比对就是查看他们的源码我们先看Collection的所有接口 public interface Collection<E> extends Iterable<E> { int size(); boolean contains(Object o); Ite

随机推荐