JDK5.0新特性

目录

1、JDK5特性

1.1、静态导入

1.2 增强for循环

1.3 可变参数

1.4 自动装箱/拆箱

1.4.1 基本数据类型包装类

1.5 枚举类

1.6 泛型

1.6.1 泛型方法

1.6.2 泛型类

1.6.3 泛型接口

1.6.4 泛型通配符


1、JDK5特性

JDK5中新增了很多新的java特性,利用这些新语法可以帮助开发人员编写出更加清晰,安全,高效的代码。

静态导入

自动装箱/拆箱

增强for循环

可变参数

枚举

泛型

1.1、静态导入

JDK 1.5 增加的静态导入语法用于导入类的某个静态属性或方法。使用静态导入可以简化程序对类静态属性和方法的调用。

语法:

import static 包名.类名.静态属性|静态方法|*

例如:

import static java.lang.System.out

import static java.lang.Math.*

import static java.lang.System.out;

import static java.lang.Math.*;

public class Demo {

    public static void main(String[] args) {

        // 普通写法

        System.out.println("hello world");

        int max = Math.max(100, 200);

        System.out.println(max);

        // 静态导入

        out.println("hello world");

        int max2 = max(100, 200);

        System.out.println(max2);

    }

}

1.2 增强for循环

引入增强for循环的原因:在JDK5以前的版本中,遍历数组或集合中的元素,需先获得数组的长度或集合的迭代器,比较麻烦!

因此JDK5中定义了一种新的语法——增强for循环,以简化此类操作。增强for循环只能用在数组、或实现Iterable接口的集合类

语法格式: 

for(变量类型 变量 :需迭代的数组或集合){}

                                       

For each是为了让你的代码变得简捷、和容易维护。

它的速度也普通遍历的速度是一致的。

1.3 可变参数

JDK中具有可变参数的类Arrays.asList()方法。

分别传多个参、传数组,传数组又传参的情况。

注意:传入基本数据类型数组的问题。

从JDK 5开始, Java 允许为方法定义长度可变的参数。

语法:数据类型…变量名。

可变长参数是Object[] 数组。(可变参数里存的是对象数组)

JDK中的典型应用:

     Arrays.asList(T…a)是jdk中的典型应用。

需求:对若干个整数进行求和

public static int sum1(int a,int b ) {

        return a+b;

    }

若干个整数求和如何解决?

可以使用数组接收整数。

public static int sum1(int[] numbers) {

        if (numbers == null) {

            return 0;

        }

        if (numbers.length == 0) {

            return 0;

        }

        int sum = 0;

        for (int num : numbers) {

            sum += num;

        }

        return sum;

    }

可以使用可变参数

public static int sum2(int... numbers) {

        if (numbers == null) {

            System.out.println("可变参数的值为null");

            return 0;

        }

        if (numbers.length == 0) {

            System.out.println("可变参数的值的长度为0");

            return 0;

        }

        int sum = 0;

        for (int num : numbers) {

            sum += num;

        }

        return sum;

    }

可变参数的使用

public static void main(String[] args) {

        // int result = sum1(new int[] { 1, 3, 5, 7, 9 });

        // System.out.println(result);

        // // 使用了可变参数,传一个数组进去

        // int result = sum2(new int[] { 1, 3, 5, 7, 9 });

        // System.out.println(result);

        // 使用了可变参数,不必声明数组,简化书写

        // int result = sum2(2, 4, 6, 8, 10);

        // int result = sum2(1);

        int result = sum2();

        System.out.println(result);

    }

可变参数的细节

声明:

      在一个方法中,最多只能有一个可变参数。

      可变参数只能放在参数列表的最后面。

   调用:

      当使用可变参数时,可以传0或多个参数。

      当使用可变参数时,也可以传一个数组进去,就表示多个参数。

   使用:

      在方法内部使用时,就是在使用一个数组。

      当调用时没有传参数时(传了0个),这时在方法内部的参数数组是有值的(不为null),但长度为0.

1.4 自动装箱/拆箱

自动装箱:指开发人员可以把一个基本数据类型直接赋给对应的包装类

自动拆箱:指开发人员可以把一个包装类对象直接赋给对应的基本数据类型。

典型应用:

   List list = new ArrayList();

   list.add(1);

   //list.add(new Integer(1));

   int i=list.get(0);

   //int j = (Integer)list.get(0);

1.4.1 基本数据类型包装类

包装类                             基本数据类型

Byte

byte

Short

short

Integer

int

Long

long

Boolean

boolean

Float

float

Double

double

Character

char

对象变基本数据类型:拆箱

基本数据类型包装为对象:装箱

为了使得java的基本类型有更多的功能,java为其所有的基本类型提供了包装类来封装常见的功能。如:最大值、数值转换等。

将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据

所属的包:java.lang.*

常见应用一:

获取最大最小值MAX_VALUE / MIN_VALUE

整数类型最大值

Integer.MAX_VALUE

System.out.println(Integer.MIN_VALUE);// -2147483648

System.out.println(Integer.MAX_VALUE);// 2147483647

应用二:

基本数据类型和字符串之间的转换

例:Integer的parseInt方法,intValue方法

基本数据类型转换成字符串:

1:基本数据类型+””

2:基本数据类型.toString(基本数据类型值);

例如  Integer.toString(34); //将34变成了”34”

基本数据类型转字符串

int i=100;

        String str=100+"";

        String string = Integer.toString(100);

字符串变基本数据类型

基本数据类型 a=基本数据类型包装类.parse基本数据类型(String str);

str="123";

        int parseInt = Integer.parseInt(str);

        System.out.println(parseInt);

注意:

public static int parseInt(String s)

Integer类中的parseInt方法是静态的 参数必须是数字格式

Double

str = "3.14";

        double parseInt2 = Double.parseDouble(str);

        System.out.println(parseInt2);

boolean b = Boolean.parseBoolean("true");

应用三:

进制转换:

 十进制转成其他进制.

toBinaryString(int i)
          以二进制(基数 2)无符号整数形式返回一个整数参数的字符串表示形式。

toHexString(int i)
          以十六进制(基数 16)无符号整数形式返回一个整数参数的字符串表示形式。

toOctalString(int i)
          以八进制(基数 8)无符号整数形式返回一个整数参数的字符串表示形式。

那么其他进制转成十进制

parseInt(String radix);

parseInt(String s, int radix)
          使用第二个参数指定的基数,将字符串参数解析为有符号的整数。

十进制转其他进制

// 十进制转二进制

        String binaryString = Integer.toBinaryString(100);

        System.out.println(binaryString); // 1100100

        // 十进制转十六进制

        String hexString = Integer.toHexString(100);

        System.out.println(hexString); // 64

        // 十进制转八进制

        String octalString = Integer.toOctalString(100);

        System.out.println(octalString); // 144

其他进制转十进制

// 字符串转对应的进制

        int parseInt3 = Integer.parseInt(octalString);

        System.out.println(parseInt3);

        // 二进制转十进制

        int parseInt4 = Integer.parseInt(binaryString, 2);

        System.out.println(parseInt4);

        // 十六进制转十进制

        int parseInt5 = Integer.parseInt(hexString, 16);

        System.out.println(parseInt5);

        // 八进制转十进制

        int parseInt6 = Integer.parseInt(octalString, 8);

        System.out.println(parseInt6);

JDK5.0后出现了自动装箱和拆箱

JDK5.0以后,简化了定义方式。

Integer x = new Integer(5);//装箱

        int intValue = x.intValue(); //拆箱

        // 5.0简化书写

        // 自动装箱。new Integer(5);

        Integer y = 5; 

        // 对象加整数,x 进行了自动拆箱,变成了int 5进行加法运算后再将和进行装箱赋给x

        y = y + 5; // 是通过Integer.intValue() 方法进行拆箱

练习:

public static void main(String[] args) {

        Integer a = 127;

        Integer b = 127;

        System.out.println(a == b);

        Integer c = 128;

        Integer d = 128;

        System.out.println(c == d);

    }

请问结果?

   a==b 为true 因为a和b指向了同一个Integer 对象.

   Integer的缓存大小-128 ~127 之间也就是byte的范围。

1.5 枚举类

有时候,变量的取值只是在一个有范围内,例如:服装的尺寸有小,中,大,和超大尺寸.我们可以将这些尺寸定义为定义变量并保存值为 1,2,3,4 或者S M L X ,这样可以解决问题.但是变量很有可能保存了一个错误的值(0 或者m)

一些方法在运行时,它需要的数据不能是任意的,而必须是一定范围内的值,此类问题在JDK5以前采用自定义带有枚举功能的类解决,Java5以后可以直接使用枚举予以解决。

例如: 交通灯(红、黄、绿)    性别(男、女)   星期(星期一、二、三…..)

     分数等级(A、B、C、D、E)

JDK 5新增的 enum 关键字用于定义一个枚举类。

枚举的实现

使用enum定义枚举类

在枚举类中定义枚举值(大写)

enum Gender {

    MALE, FEMALE;

}

使用javap命令

发现其中每一个枚举值都是枚举类的具体实例对象.只不过是静态常量.

枚举类具有如下特性:

枚举类也是一种特殊形式的Java类。

枚举类中声明的每一个枚举值代表枚举类的一个实例对象。

与java中的普通类一样,在声明枚举类时,也可以声明属性、方法和构造函数.

public class Demo1 {

    public static void main(String[] args) {

        Gender male = Gender.MALE;

        System.out.println(male.getInfo());

    }

}

enum Gender {

    MALE(""), FEMALE;

    // 成员变量

    private String info;

    // 构造函数

    private Gender() {

    }

    private Gender(String info) {

        this.info = info;

    }

    // 成员方法

    public String getInfo() {

        return info;

    }

}

枚举类可以声明抽象方法,但是要有具体的枚举值去实现.

public class Demo1 {

    public static void main(String[] args) {

        Gender male = Gender.MALE;

        System.out.println(male.getInfo());

        male.speak();

    }

}

enum Gender {

    MALE("") {

        @Override

        public void speak() {

            System.out.println("是男人");

        }

    },

    FEMALE {

        @Override

        public void speak() {

            System.out.println("是女人");

        }

    };

    // 成员变量

    private String info;

    // 构造函数

    private Gender() {

    }

    private Gender(String info) {

        this.info = info;

    }

    // 成员方法

    public String getInfo() {

        return info;

    }

    public abstract void speak();

}

枚举类也可以实现接口(序列化)、或继承抽象类。

JDK5中扩展了swith语句,它除了可以接收int, byte, char, short外,还可以接收一个枚举类型(enum)

public class Demo2 {

    public static void main(String[] args) {

        WeekDay mon = WeekDay.MON;

        switch (mon) {

        case MON:

            System.out.println("星期一要上班...");

            break;

        case TUE:

            System.out.println("星期二,继续上班...");

            break;

        }

    }

}

enum WeekDay {

    MON, TUE, WED, THU, FRI, SAT, SUN;

}

若枚举类只有一个枚举值,则可以当作单态设计模式使用。

练习:

请编写一个关于星期几的枚举WeekDay,要求:枚举值:Mon,Tue,Wed,Thu,Fri,Sat,Sun 该枚举要有一个方法,调用该方法返回中文格式的星期。

enum WeekDay {

    MON {

        @Override

        public String getInfo() {

            return "星期一";

        }

    },

    TUE {

        @Override

        public String getInfo() {

            return "星期二";

        }

    },

    WED {

        @Override

        public String getInfo() {

            return "星期三";

        }

    },

    THU {

        @Override

        public String getInfo() {

            return "星期四";

        }

    },

    FRI {

        @Override

        public String getInfo() {

            return "星期五";

        }

    },

    SAT {

        @Override

        public String getInfo() {

            return "星期六";

        }

    },

    SUN {

        @Override

        public String getInfo() {

            return "星期天";

        }

    };

    public abstract String getInfo();

}

1.6 泛型

1.6.1 泛型方法

需求:写一个函数,调用者传递什么类型的变量,该函数就返回什么类型的变量?

实现一:

由于无法确定具体传递什么类型的数据.那么方法的形参就定义为Object类型.返回值也就是Object类型.但是使用该函数时需要强制类型转换.

private Object getDate(Object obj) {

       return obj;

}

当不进行强制类型转换能否写出该功能?

目前所学的知识无法解决该问题

就需要使用泛型类解决

使用的泛型的自定义来解决以上问题。

泛型: 就是将类型当作变量处理。规范泛型的定义一般是一个大写的任意字母。

1. 函数上的泛型定义

         当函数中使用了一个不明确的数据类型,那么在函数上就可以进行泛型的定义。

        public <泛型的声明> 返回值类型  函数名( 泛型 变量名  ){

        }

public static void main(String[] args) {

       int[] arr = { 1, 2, 3, 4, 5 };

       new Demo6().getData(5);

    }

    public <T> T getData(T data) {

       return data;

    }

细节:

使用泛型方法前需要进行泛型声明,使用一对尖括号 <泛型>,声明的位置在static后返回值类型前。

当一个类中有多个函数声明了泛型,那么该泛型的声明可以声明在类上。

1.6.2 泛型类

格式

2. 类上的泛型声明

         修饰符 class 类名<泛型>{

         }

import java.util.Arrays;

public class Demo6<T> {

    public static void main(String[] args) {

       // 使用泛型类,创建对象的时候需要指定具体的类型

       new Demo6<Integer>().getData(5);

    }

    public T getData(T data) {

       return data;

    }

    // 反序任意类型数组

    public void reverse(T[] arr) {

       int start = 0;

       int end = arr.length - 1;

       for (int i = 0; i < arr.length; i++) {

           if (start < end) {

              T temp = arr[start];

              arr[start] = arr[end];

              arr[end] = temp;

           }

       }

}

在泛型类中定义一个静态方法

public class Demo6<T> {

   public static void main(String[] args) {

      System.out.println(getData2(100));

   }

   public T getData(T data) {

      return data;

   }

   //静态方法

   public static T getData2(T data) {

      return data;

   }

}

注意:静态方法不可以使用类中定义的泛型

因为类中的泛型需要在对象初始化时指定具体的类型,而静态优先于对象存在。那么类中的静态方法就需要单独进行泛型声明,声明泛型一定要写在static后,返回值类型之前

泛型类细节:

1、创建对象的时候要指定泛型的具体类型

2、创建对象时可以不指定泛型的具体类型(和创建集合对象一眼)。默认是Object,例如我们使用集合存储元素的时候没有使用泛型就是那么参数的类型就是Object

3、类上面声明的泛型只能应用于非静态成员函数,如果静态函数需要使用泛型,那么

需要在函数上独立声明。

4、如果建立对象后指定了泛型的具体类型,那么该对象操作方法时,这些方法只能操作一种数据类型。

5、所以既可以在类上的泛型声明,也可以在同时在该类的方法中声明泛型。

泛型练习:

定义泛型成员

public class Demo7 {

    public static void main(String[] args) {

       Father<String> f = new Father<String>("jack");

       System.out.println(f.getT());

       Father<Integer> f2 = new Father<Integer>(20);

       System.out.println(f2.getT());

    }

}

class Father<T> {

    private T t;

    public Father() {

    }

    public Father(T t) {

       super();

       this.t = t;

    }

    public T getT() {

       return t;

    }

    public void setT(T t) {

       this.t = t;

    }

}

如果Father类有子类,子类该如何实现

public class Demo7 {

    public static void main(String[] args) {

       Father<String> f = new Father<String>("jack");

       System.out.println(f.getT());

       Father<Integer> f2 = new Father<Integer>(20);

       System.out.println(f2.getT());

    }

}

class Father<T> {

    private T t;

    public Father() {

    }

    public Father(T t) {

       super();

       this.t = t;

    }

    public T getT() {

       return t;

    }

    public void setT(T t) {

       this.t = t;

    }

}

//子类指定了具体的类型

class Son extends Father<String>{

}

//子类也需要使用泛型

class Son3<T> extends Father<T>{

}

//错误写法,父类上定义有泛型需要进行处理

class Son2 extends Father<T>{

}

1.6.3 泛型接口

public class Demo8 {

    public static void main(String[] args) {

       MyInter<String> my = new MyInter<String>();

       my.print("泛型");

       MyInter2 my2 = new MyInter2();

       my.print("只能传字符串");

    }

}

interface Inter<T> {

    void print(T t);

}

// 实现不知为何类型时可以这样定义

class MyInter<T> implements Inter<T> {

    public void print(T t) {

       System.out.println("myprint:" + t);

    }

}

//使用接口时明确具体类型。

class MyInter2 implements Inter<String> {

    @Override

    public void print(String t) {

       System.out.println("myprint:" + t);

    }

}

1.6.4 泛型通配符

需求:

定义一个方法,接收一个集合对象(该集合有泛型),并打印出集合中的所有元素。

例如集合对象如下格式:

Collection<Person> coll = new ArrayList<Person>();

       coll.add(new Person("jack", 20));

        coll.add(new Person("rose", 18));

       Collection<Object> coll2 = new ArrayList<Object>();

       coll2.add(new Object());

       coll2.add(new Object());

       coll2.add(new Object());

       Collection<String> coll3 = new ArrayList<String>();

       coll3.add("abc");

       coll3.add("ddd");

       coll3.add("eee");

分析,集合对象中的元素的类型是变化的,方法的形参的那么泛型类型就只能定义为Object类型.

import java.util.ArrayList;

import java.util.Collection;

import java.util.HashSet;

import java.util.Iterator;

public class Demo9 {

    public static void main(String[] args) {

        ArrayList<Object> arr = new ArrayList<Object>();

       arr.add(new Object());

       arr.add("String");

       print(arr);

      

       //将集合的泛型设置类String类型,是Object子类

       HashSet<String> hs = new HashSet<String>();

       hs.add("hello");

       hs.add("jack");

       //由于print方法接收的集合进行了元素限定,只接受限定为Object类型的集合,编译不通过

       //print(hs);

    }

    public static void print(Collection<Object> coll) {

       Iterator<Object> it = coll.iterator();

       while (it.hasNext()) {

           Object next = it.next();

           System.out.println(next);

       }

    }

}

但是,由于print方法接收的集合进行了元素限定,只接受限定为Object类型的集合,编译不通过该问题如何解决?

可以把方法的形参的泛型去掉,那么方法中就把集合中的元素当做Object类型处理.

也可以使用使用泛型通配符

public class Demo9 {

    public static void main(String[] args) {

       ArrayList<Object> arr = new ArrayList<Object>();

       arr.add(new Object());

       arr.add("String");

       print(arr);

        // 将集合的泛型设置类String类型,是Object子类

       HashSet<String> hs = new HashSet<String>();

       hs.add("hello");

       hs.add("jack");

       // 使用泛型通配符,编译通过。

       print(hs);

    }

    public static void print(Collection<?> coll) {

       Iterator<?> it = coll.iterator();

       while (it.hasNext()) {

           Object next = it.next();

           System.out.println(next);

       }

    }

}

上述就使用了泛型通配符

通配符:?

public void show(List<?> list){

}

可以对类型进行限定范围。

?extends E: 接收E类型或者E的子类型。

? super E: 接收E类型或者E的父类型。

限定泛型通配符的边界

限定通配符的上边界:

extends

接收Number 类型或者Number的子类型

正确:Vector<? extends Number> x = new Vector<Integer>();

错误:Vector<? extends Number> x = new Vector<String>();

限定通配符的下边界

super

接收Integer 或者Integer的父类型

正确:Vector<? super Integer> x = new Vector<Number>();

错误:Vector<? super Integer> x = new Vector<Byte>();

总结:

JDK5中的泛型允许程序员在编写集合代码时,就限制集合的处理类型,从而把原来程序运行时可能发生问题,转变为编译时的问题,以此提高程序的可读性和稳定

注意:泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛形的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。

泛型的基本术语,以ArrayList<E>为例:<>念着typeof

ArrayList<E>中的E称为类型参数变量

ArrayList<Integer>中的Integer称为实际类型参数

整个称为ArrayList<E>泛型类型

整个ArrayList<Integer>称为参数化的类型ParameterizedType

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/625128.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

5.10 mybatis之useActualParamName作用

文章目录 1. useActualParamNamefalse1.1 单个参数映射1.2 多个数1.3 param注解 2. useActualParamNametrue useActualParamName官方解释&#xff1a;允许使用方法签名中的名称作为语句参数名称。 为了使用该特性&#xff0c;你的项目必须采用 Java 8 编译&#xff0c;并且加上…

Linux内核之aligned用法实例(四十七)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

KaiwuDB CTO 魏可伟:AIoT,用行业定义数据库

4月12日&#xff0c;由中国 DBA 联盟&#xff08;ACDU&#xff09;与墨天轮社区联合主办的第十三届数据技术嘉年华&#xff08;DTC 2024&#xff09;于北京盛大召开。KaiwuDB CTO 魏可伟受邀发表《智创当下&#xff0c;KaiwuDB 从多模到 AI 的探索实践》主题演讲&#xff0c;向…

看图找LOGO,基于YOLOv8全系列【n/s/m/l/x】参数模型开发构建生活场景下的商品商标LOGO检测识别系统

日常生活中&#xff0c;我们会看到眼花缭乱的各种各样的产品logo&#xff0c;但是往往却未必能认全&#xff0c;正因为有这个想法&#xff0c;这里我花费了过去近两周的时间采集和构建了包含50种商品商标logo的数据集&#xff0c;基于YOLOv8全系列的参数模型开发构建了对应的检…

2016NOIP普及组真题 1. 金币

线上OJ&#xff1a; 一本通&#xff1a;http://ybt.ssoier.cn:8088/problem_show.php?pid1969 核心思想&#xff1a; 解法1、由于数据量只有 10000 天&#xff0c;估可以采用 模拟每一天 的方式。 #include <bits/stdc.h> using namespace std;int k 0;int main() {i…

地质灾害监测预警系统:科技守护,构筑智能预警屏障

随着全球气候变化和人为活动的加剧&#xff0c;地质灾害频繁发生&#xff0c;给人们的生命财产安全带来了严重威胁。为了降低地质灾害带来的损失&#xff0c;地质灾害监测预警系统应运而生。本文将为您详细介绍地质灾害监测预警系统的原理、功能以及在实际应用中的效果。 一、地…

如何从零开始创建React应用:简易指南

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

C#通用类库封装实战

数据库查询 特性方式获取数据库列的别名 数据库更新 使用简单工厂配置的方式

企业邮箱迁移是什么?如何通过IMAP/POP协议进行邮箱迁移?

使用公司邮箱工作的过程中&#xff0c;公司可能遇到公司规模的扩大或技术架构升级&#xff0c;可能要换公司邮箱。假如马上使用新的公司邮箱&#xff0c;业务处理要被终断。企业邮箱转移是公司更换邮箱不可或缺的一步&#xff0c;不仅是技术操作&#xff0c;更是企业信息安全、…

【央国企专场】——军工研究所

研究所目录 一、企业概述1.1 中国航天1.2 中国电科1.3 中国船舶1.4 中国兵器 二、招聘信息2.1 中国航天2.2 中国电科2.3 中国船舶2.4 中国兵器 一、企业概述 在校招中会有很多企业来学校开宣讲会&#xff0c;其中就有许多广为人知的军工研究所&#xff0c;比如&#xff1a;中国…

“中医显示器”是人体健康监测器

随着科技的进步&#xff0c;现代医学设备已经深入到了人们的日常生活中。然而&#xff0c;在这个过程中&#xff0c;我们不应忘记我们的医学根源&#xff0c;中医。我们将中医的望、闻、问、切四诊与现代科技相结合&#xff0c;通过一系列的传感器和算法将人体的生理状态以数字…