代码编织梦想

JAVA三大块:

-JAVASE(JAVA标准版)

-JAVAEE(JAVA企业版)

-JAVAME(JAVA微型版)

JAVA语言特性

*简单性

*面向对象

JAVA是纯面向对象的更符合人的思维,容易理解

*可移植性

JAVA程序可做到一次编译,到处运行

JAVA可以在多个系统上运行被称为可移植性,或者叫跨平台。

*多线程

*健壮性

有自动垃圾回收机制 机制简称GC机制。

JAVA语言运行过程中产生的机制是自动回收的

不需要程序员的关心

*安全性

JAVA语法笔记:

输入函数

import java.util.Scanner;//主函数以外代码(主函数以内如果要有输入函数【主函数外必须得写它】)

Scanner scanner=new Scanner(System.in);//放在主函数内(主函数内要有输入函数【就必须得有它】)
     String name = scanner.next();//往定义字符串变量里面输入值
 int score=scanner.nextInt();//输入int类型得.nextInt();
     int i= scanner.nextInt();//用法和上面一样

包装类找到数据类型最大与最小值

(int类型是个特例 _VALUE前要写成Integer,【其他变量类型只写自己本身】)

int i= Integer.MIN_VALUE;||int i= Integer.MAX_VALUE;
        System.out.println(i);//输出int类型的最小值\或最大值;

float y=Float.MAX_VALUE;
        System.out.println(y);//包装类(判断变量类型范围)
loat i2=Float.MAX_VALUE;
        System.out.println(i2);
//运行结果3.4028235E38  E38表示10的38次方

   float i2=3.14f;//强制转换3.14后加f 强制转换成float 不加f报错
        System.out.println(i2);

char c=Character.MAX_VALUE;
        System.out.println((int)c);//char类型没有负数的概念最大65535 最小0

布尔 boolean(不是数值 只是一对真假)

boolean boll=false;
        boolean boll1=true;
        System.out.println(boll);
        System.out.println(boll1);

强制转换语法:(数据类型)(表达式)

例子:double p=10;//数据类型以最大的为准 (出现报错要警醒强制转换)
        int u=11;
        int y=(int)(u+p);

关系运算符号

> >= < <= == !=

        int a=10;
        int b=10;
        boolean r1=a>b; //boolean就是判断变量的真假(数据类型)
        boolean r2=(a==b);
        boolean r3=a<b;
        System.out.println(r1);//false
        System.out.println(r2);//true
        System.out.println(r3);//false 

if语句核心结构:

if(条件){//条件真假

代码片段1;

}else{

代码片段2

}

boolean flag = true;
        if (flag){
            System.out.println("真");
        }else{
            System.out.println("假");
        }

随机数

//随机产生一个0~9之间的随机数的代码

Math.random()产生一个左闭右开[0.0~1.0)之间的一个小数

目标产生0~9之间的数,一共10个

[0.0~1.0)*10->[0.0~1.0)->强转[0~10)

int luck=(int)(Math.random()*10);

import java.util.Random;

public class suiji {
    public static void main(String[] args) {
        Random random=new Random();
        System.out.println(random);
        int date=random.nextInt(100);//生成0~99的随机数
        System.out.println(date);
    }
}
   int date=random.nextInt(10)+1;//随机生成1~10之间的数
        System.out.println(date);
        System.out.println("---------------------------------");
        int date1=random.nextInt(15)+3;//随机生成3~17之间的数
                                                 nextInt(15)生成0~14之间的数
        System.out.println(date1);

CTRL+ALT+T查找自己想用结构的快捷键

变量.equals("")

用于基本数据类型(byte short int long float double char boolen)比较

字符串 string 比较用equals()

Scanner scanner=new Scanner(System.in);
        System.out.print("请输入字母");
        String a=scanner.next();
        if (a.equals("y")){//字符串比较用equals()
            System.out.println("真");
        }else {
            System.out.println("假");
        }

switch(a){}选择语句

a可以是char Byte int short String 等类型(不能是 double float 等类型)

类名与全类名
mport java.util.Scanner;//全类名

public class 抽奖游戏 {
    public static void main(String[] args)  {
        Scanner scanner=new Scanner(System.in);//Scanner 类名


 if(birthday.length()==5)//判断字符数组是否是五位 

数组:

//声明一个数组(与C语言定义数组区别很大)

int[] arr;或者 int arr[]; arr=new int[5]; int qq[]=new int[5];

int arr[]=new int[]{12,2,90,78};//直接给数组赋值
int arr[]={12,2,90,78};//(如果 声明 分配空间在一行 可直接省略 new in[])
//不给数组赋值 数组里面变量的默认值为0
System.out.println(arr.length);//.lenth是判断数组长度
运行结果:4
 boolean hh=false;
 for (int j=0;j<arr.length;j++){
            if (number==arr[j]){
                hh=true;
                break;
            }
        }
        System.out.println(hh?"找到了":"没找到");//就是C中三目运算的写法

Arrays排序(从小到大 升序排列)

int qq[]=new int[]{12,34,56,124,77,1,2};
          System.out.println(qq);//直接打印数组地址 运行地址:[I@7ea987ac
                                  ( [代表一维数组   I代表整型(int) @代表8位16进制内存地址)
--------System.out.println(Arrays.toString(qq));//将数组地址还原成(翻译)数组
此行运行结果:[12, 34, 56, 124, 77, 1, 2]
        Arrays.sort(qq);//将数组进行排序
        for (int i=0;i<qq.length;i++){
            System.out.print(qq[i]+" ");
        }
运行结果:1 2 12 34 56 77 124

rrays.equals(arr1,arr2))

int arr2[]={12,3,13,6,7,2,3};
        int arr1[]={12,3,13,6,7,2,3};
        System.out.println(Arrays.equals(arr1,arr2));//判断亮个数组是否相同 相同true 否则 false

Arrays.fill(arr1,val:11);

将11全部赋给数组arr1(注意:val:11这个地方输入时直接输11 )

int arr2[]={12,3,13,6,7,2,3};
        int arr1[]={12,3,13,6,7,2,3};
        Arrays.fill(arr1,val:11);//将11全部赋给数组arr1(注意:val:11这个地方输入时直接输11 )
        System.out.println(Arrays.toString(arr1));
运行结果:[11, 11, 11, 11, 11, 11, 11]

Arrays.copyOf(arr2,newlenth:2)

限制数组长度只有两个值(注意:newlenth这个地方输入时直接输2)

int arr2[]={12,3,13,6,7,2,3};
        int arr1[]={12,3,13,6,7,2,3};
        System.out.println(Arrays.toString(Arrays.copyOf(arr2,newlenth:2)));
//Arrays.copyOf(arr2,newlenth:2)限制数组长度只有两个值(注意:newlenth这个地方输入时直接输2)
运行结果:[12, 3]

Arrays.binarySearch(arr2,key:2)

查找指定元素下标 (根据从小到大的顺序查找下标)

如果没有找到对应元素的下标 返回插入点下标取反在减1

例子 [2, 3, 5, 6, 7, 12, 13]

查找4这个元素 但数组并没有元素4 但元素4位于元素3与元素5之间

所以从元素3后面找下标 下标是2 2在取反就是-2 在减1 就是-3

所以运行结果是-3

 int arr2[]={12,3,13,6,7,2,3};
 Arrays.sort(arr2);//升序排列
        System.out.println(Arrays.toString(arr2));//将数组进行从小到大排序
        int pos=Arrays.binarySearch(arr2,key:2);//查找指定元素下标 前提得是数组得从小到大排序(根据从小到大的顺序查找下标)
                                                 注意:key:2 这个地方只需要输入11
        System.out.println(pos);

字符数组排列

char arr3[]={'a','y','c','b','e'};
        Arrays.sort(arr3);
        System.out.println(Arrays.toString(arr3));//升序排列
        for (int i = arr3.length - 1; i >= 0; i--) {//降序排列(降序排列之前得升序)
            System.out.println(arr3[i]+" ");
        }

函数的调用

public class 函数 {
    public static void main(String[] args) {
        f01();
          f03(3,90);
    }
   public static void f01(){              //公共访问修饰符 public  静态的static  没有返回值的viod
       System.out.println("你个大傻叉");
   }
       public static int f02(){             //返回值的调用 
        System.out.println("你个二傻叉");
        return 100;
    }
       public static void f03(int age,int find) {
        System.out.println("年龄" + age + "身高" + find);
    }
}

函数重载原则:

方法名相同 参数列表不同 注意:与返回值无关

public static void main(String[] args) {
        f01(999999999.9999);
}
   public static void f01(int age){
        System.out.println("f01");
    }
    public static void f01(double age){
        System.out.println("f02");
    }
运行结果:double age

如果f01(1)
运行结果:int age

往函数里传数组

public static void main(String[] args) {
        f01(new  int []{12,9,4,32,44});

    }
    public static void f01(int... arr){//往函数里面传数组得打 ...
        System.out.println("int age");
        Arrays.sort(arr);
        for (int i = arr.length - 1; i >= 0; i--) {
            System.out.println(arr[i]);
        }
    }
 
自动循环arr数组 知道何时结束 每次输出完把变量放到a变量上
public static void main(String[] args) {
        f01(new int[]{12, 9, 4, 32, 44});
}
//自动循环arr数组 知道何时结束 每次输出完把变量放到a变量上
    public static void f01(int... arr) {//只要有三个点 arr十个数组(...代表可变参数)
        System.out.println("int age");
        for (int a : arr) {// foreach输出
            System.out.println(a);
        }
    }

charAt()

方法用于返回指定索引处的字符。索引范围为从 0 到 length() - 1。

String s = "www.runoob.com";
        char result = s.charAt(6);
        System.out.println(result);
运行结果:n

.close

释放内存

Scanner scanner =new Scanner(System.in);
        scanner.close();//关闭scannner 同时释放内存

math.round()四舍五入

ji=6,n=7;
System.out.println(Math.round(ji*100/n) + "%");
运行结果:71%

System.out.println(String.valueOf(9));//String.valueOf(9)将指定数值转换为字符串(不确定)

通过JAVA打开文件

public class 递归调用 {
    public static void main(String[] args) {
            Showfile(new File("E:\\JAVA实践文件夹"));
    }
    public static void Showfile(File file){
        File files[]=file.listFiles();
        for (File f:files){
            if (f.isFile()) System.out.println(f.getName());
             //.isFile确定f是否为文件 如果是文件 就取出来
            if (f.isDirectory()) Showfile(f);
        //如果是文件夹 就调用自己
        }
    }
}
运行结果:
a.txt
文少.txt

面向过程——>面向对象

业务分门别类起来 设计成一个一个类 使用类生成对象

创建类

School类:
属性名1
属性名2
属性名3
用法:
展示结果
public class School {
    //属性
    String name;
    int teacher;
    int jfnumber;
//方法
    public  void show(){
System.out.printf("%x",this.hashCode());//将内存地址打印出来
        System.out.println("名称 "+name+"老师 "+teacher+"机房 "+jfnumber);
    }
}
public class 哈哈类 { //直接调用class属性
    public static void main(String[] args) {
        //声明
          School xuexiao;
          //分配空间
          xuexiao =new School();
          xuexiao.name="万科小学";
          xuexiao.teacher=10;
          xuexiao.jfnumber=10;
          //访问方法
xuexiao.show();
    }
}
运行结果: 7ea987ac 名称 万科小学老师 10机房 10

.getClass();//获得当前对象类型

System.out.println("kkk".getClass());
运行结果:class java.lang.String
public class Custom {
    String type;
    int jf;
    public void show(){//show()内部有个变量叫this 接受住 custom1与custom2的值
        System.out.printf("%x",this.hashCode());//将内存地址打印出来
        System.out.println("会员:"+type+" 积分"+jf);
    }


public class 两个类 {
    public static void main(String[] args) {
        Custom custom1=new Custom();
        Custom custom2=new Custom();
        custom1.type="黑金";
        custom1.jf=8888;
        custom2.type="白金";
        custom2.jf=9998;
        custom1.show();
        custom2.show();
    }
}
运行结果:
1b6d3586会员:黑金 积分8888
7ea987ac会员:白金 积分9998
thisGC回收机制
public class Custom {
    String type;
    int jf;
    public void show(){//show()内部有个变量叫this 接受住 custom1与custom2的值
        System.out.printf("%x",this.hashCode());//将内存地址打印出来
        System.out.println("会员:"+type+" 积分"+jf);
    }


public class 两个类 {
    public static void main(String[] args) {
        Custom custom1=new Custom();
        Custom custom2=new Custom();
        custom1.type="黑金";
        custom1.jf=8888;
        custom2.type="白金";
        custom2.jf=9998;
        custom1.show();
        custom2.show();
    }
}
运行结果:
1b6d3586会员:黑金 积分8888
7ea987ac会员:白金 积分9998
public class 回收机制 {
    public static void main(String[] args) {
        {
            School school1 = new School();//new分配一块堆
            //GC的垃圾回收机制 记录这块内存引用数为1
            school1.name = "jjjj";
            school1.show();
            //school1回收了 GC感应机制感应到school1被回收了 引用变量0
            //GC回收机制就会考虑回收
           }
            System.gc();//主动调用GC垃圾回收
    }
}

printf输出

用printf输出 可以识别%d %x %o 一些数字的输出

System.out.printf("八进制:%o,十进制:%d,十六进制:%x",20,20,20);

运行结果: 八进制:24,十进制:20,十六进制:14

字符串类的使用

compareTo()

compareTo() 方法用于将 Number 对象 与方法的参数进行比较。(强调是用 对象 比较 )

如果指定的数与参数相等返回 0。

如果指定的数小于参数返回 -1。

如果指定的数大于参数返回 1。

public class Test{ 
   public static void main(String args[]){
      Integer x = 5;
      System.out.println(x.compareTo(3));
      System.out.println(x.compareTo(5));
      System.out.println(x.compareTo(8));            
     }
}
运行结果:
 1
 0
-1

isLetter()方法用于判断指定字符是否为字母。

System.out.println(Character.isLetter('c'));

isDigit()

方法用于判断指定字符是否为数字。

isUpperCase() 方法用于判断指定字符是否为大写字母。

isLowerCase() 方法用于判断指定字符是否为小写字母。

toUpperCase() 方法用于将小写字符转换为大写。

toLowerCase() 方法用于将大写字符转换为小写。

Java StringBuffer 和 StringBuilder 类

StringBuilder sb=new StringBuilder(10);//给字符串10个内存空间
        sb.append("hello");
        System.out.println(sb);
        sb.insert(1,"...");
        System.out.println(sb);
      sb.delete(0,1);
        System.out.println(sb);
运行结果:
hello
h...ello
...ello
StringBuffer sBuffer = new StringBuffer("菜鸟教程官网:");
    sBuffer.append("www");
    sBuffer.append(".runoob");
    sBuffer.append(".com");
    System.out.println(sBuffer);  
运行结果:
菜鸟教程官网:www.runoob.com

OUT结束-

OUT:标记从哪里结束

while (true){
            System.out.println("请输入你要猜的数字");
            int a=scanner.nextInt();
            for (int i = 0; i < arr.length; i++) {
                if (arr[i]== a) {
                    System.out.println("才对了");
                    break OUT;//有这个OUT 结束整个while()的循环 没OUT直接结束for循环
                }
            }

方法重载

数组往方法传的形参是地址值 而变量传的往方法传的形参是值

基本数据类型是传值 引用数据类型是传址(数组)(字符串)等

只要在同一个类中,方法名相同,形参列表不同,他们就是重载的方法

集合

ArrayList<Object> STU=new ArrayList<>();//Object代表任意对象都能加进去

ArrayList list=new ArrayList();
        list.add("java");//给集合添加元素
        list.add("myscl");
        list.add(12);
        list.add(0,90);
        System.out.println(list.get(0));//list.get(0)访问下标列表中下标为0的数组
运行结果:90
ArrayList<Integer> list1=new ArrayList();//定义集合类 只能放入整形的元素
        list1.add(90);
        list1.add(0,7);
        System.out.println(list1);
    System.out.println(list1.size());//统计列表中元素个数

运行结果:2
       [7, 90]
ArrayList<String> list2 = new ArrayList();
        list2.add("java");
        list2.add("myscl");
        list2.add("python");
        System.out.println(list2);
System.out.println(list2.remove("myscl"));//删除成功用true 删除失败用flase
        String e = list2.remove(0);
        System.out.println(e);
        System.out.println(list2);
运行结果:[java, myscl, python]
    true
    java
    [myscl, python]

总结 : .add() 添加元素

.size() 统计元素个数

.remove() 删除元素 (如果一个元素出现两次默认删除第一次出现的元素)

.set(下标,元素) 修改元素

.get() 通过下标获取元素

验证码代码

package mm;
import java.util.Random;
public class yanm {
    public static void main(String[] args) {
        System.out.println("验证码是:"+greatcode(5));
    }
    public static String greatcode(int n){
        String code="";//存随机的各种字符的变量
        Random random=new Random();
        for (int i = 0; i < n; i++) {
                int type=random.nextInt(3);//随机三种字符
                switch (type){
                    case 0:
                        char ch=(char)(random.nextInt(26)+65);//随机大写字符
                        code+=ch;
                        break;
                    case 1:
                        char ch1=(char)(random.nextInt(26)+97);//随机小写写字符
                        code+=ch1;
                        break;
                    case 2:
                        code+=random.nextInt(10);//随机数字
                }
                //随机三种字符循环N次进行拼接
        }
        return code;
    }
}

构造器

有参 无参构造器

public class Car {//自定义的类
    String name;
    int n;
    public Car(String name1, int n1){
        System.out.println("有参构造器被调用");
        name=name1;
        n=n1;
    }
}
--
public class cars {
    public static void main(String[] args) {
        Car car=new Car("呵呵",90);//无参Car里面不放参数
        System.out.println(car.name);
        System.out.println(car.n);
    }
}
运行结果:
有参构造器被调用
呵呵
90

this关键字

this关键字出现在构造器和成员方法中 代表当前对象的地址

this可以指定访问当前对象的成员

字符串对象特点

双引号创建的字符串,在字符串常量池中存储一个 (前提是两个字符串一样)

通过new构造创建的字符串对象,在内存中分开存储(分配两块内存,内存地址不一样)

字符串与字符串的比对 可以用 字符串.equalsIgnoreCase(字符串) (只比对字符串内容不看字符串字母大小)

快捷键 ctrl+alt+t 为内容加循环

快捷键 alt+回车 自动生成方法

static关键字

修饰的成员变量 静态成员变量 只在内存中存一份

静态成员变量有:有static修饰;属于类,可以被共享发布访问

同一个类中,访问静态方法,类名可以不写

public static a=161;

public class Class {
    public static int a(int a,int b){
        return a>b?a:b;
    }

    public static void main(String[] args) {
        System.out.println(Class.a(10,3));
        System.out.println(a(10,3));//类名可以省略
    }
}
public class Class {
private String name;
public void run(){
    System.out.println(name+"再跑");
    }
    //静态方法能访问静态成员不能访问实例成员(可以间接访问 比如调用创建的类)
    public static void main(String[] args) {//实例方法可以访问静态成员也可以访问实例成员
       // System.out.println(Class.run);错误写法访问不了run()
    }

}

this 只能代表当前对象

实例方法可以访问静态成员也可以访问实例成员 静态方法不能直接访问实例成员

当前对象的地址只能放在实例对象里 静态对象不能出现关键字

由于工具类无需创建对象 把构造器私有化显得很专业

代码块

作用:可以用于初始化静态资源

public class kuai {
    static {
        System.out.println("------代码块被调用了-----------");
    }
    public static void main(String[] args) {
        System.out.println("-------main()方法被执行----------");
    }
}
运行结果:------代码块被调用了-----------
         -------main()方法被执行----------

子类继承父

子类 this

父类 super

子类不可以继承父类构造器,父类构造器用于初始化父类对象

子类可以直接使用父类的静态成员(共享)就是子类可以使用父类的东西 但这个东西并不属于子类

一个子类只能继承一个父类

如果子类一定要用父类的成员一定在父类的成员前加 super(在子类成员和父类成员重名的情况下)

public class tex1 {
    public static void main(String[] args) {
        New OP = new New();
        OP.call();
        //   hw.call();
    }
}

class New extends phone {
    @Override  注解校验是否正确同时可读性好//重写的方法的名词和形参列表必须和被重写的方法一样 私有方法不能被重写
            静态(static)方法不能被重写
     public void call() {
        super.call();//调用父类的方法
        System.out.println("打游戏");
    }
    @Override
    public void send() {
        super.send();
        System.out.println("发短信");
    }
}
class phone {
    public void call() {
        System.out.println("打电话");
    }

    public void send() {
        System.out.println("发短信");
    }
}

子类构造器执行时先会调用父类的无参构造器 然后在执行子类自己的构造器

调用父类有参构造器

想调用父类的有参构造器
 public People(String name, int phone) {
public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getPhone() {
        return phone;
    }
    public void setPhone(int phone) {
        this.phone = phone;
    }
    String name;
    int phone;
        this.name = name;
        this.phone = phone;
    }
----------
public class Teacher extends People{
     public Teacher(String name,int phone){
        super(name,phone);//向父类传参数传到People类
     }
}
----------
public class jicgouzq {
    public static void main(String[] args) {
        Teacher t=new Teacher("呵呵呵",900);
        System.out.println(t.getPhone()+t.getName());
    }
}

super()构造器和this()构造器必须放在第一行 两者不可放在一起 方法有弗雷先走父类

final语法

final修饰类不能被继承

final修饰方法不能被重写

//方法重写
public class Test1 {
    public static void main(String[] args) {
        Stu stu=new Stu();
        stu.eat();
        People people=new People();
        people.eat();
    }
}
class Stu extends People{
    public static void eat(){
        System.out.println("吃个屁");
    }
}

class  People{
    public final  static void eat(){//如果加了final Stu这个类无法访问eat()这个方法
        System.out.println("吃冬秀");
    }
}

变量或者方法加final那么方法就只能用一次 变量只能赋一次值

public static final String name="xji";//只能放在类里 表常量

abstract抽象类

如果一个类中定义了抽象方法,这个类必须声明为抽象类

子类继承父类的抽象方法 子类要重新生成方法(快捷键:alt+回车 生成方法 光标放在子类)

子类继承父类的抽象方法 父类的方法由子类重写

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/wangziwen_/article/details/129433823

Java基础练习题及详细答案-爱代码爱编程

本文参考 嗨客网 Java 实战 前言 本篇文章给大家安利一些关于 Java 基础的练习题,每道题都附有答案链接,答案解题的每个步骤到运行结果都十分详细,十分适合小白拿来练习,也十分适合准备面试的各位复习下 Java 基础,这篇文章我会不断更新,题目都是对应 Java 基础中的各个知识点,大家在学习了Java 基础之后,做几道相关的练习题,复

java基础知识点-爱代码爱编程

原文的链接 Java基础知识总结(超详细整理) Java语言的特点 1.面向对象 面向对象(OOP)就是java语言的基础,也是Java语言的重要特性。面向对象的概念:生活中的一切事物都可以被称之为对象,生活中随处可见的事物就是一个对象,我们可以将这些事物的状态特征(属性)以及行为特征(方法)提取并出来,并以固定的形式表示。 2.Java语法

超全!java基础知识点总结_今天你学编程了吗的博客-爱代码爱编程

本文主要是我之前复习Java基础原理过程中写的Java基础知识点总结。Java的知识点其实非常多,并且有些知识点比较难以理解,有时候我们自以为理解了某些内容,其实可能只是停留在表面上,没有理解其底层实现原理。 纸上得来终觉浅,绝知此事要躬行。笔者之前对每部分的内容对做了比较深入的学习以及代码实现,基本上比较全面地讲述了每一个Java基础知识点,当然可能有

java基础(java发展及基础详解,安装)_柒分、的博客-爱代码爱编程

一、Java的概述 1.1、Java的发展史 1995年由SUN开发的 2009年被Oracle收购,发布了Java1.5 Java发行的版本: JavaME:小型的Java嵌入式程序JavaSE:标准

java基础语法_java的基本语法-爱代码爱编程

一、 基础语法 Java大小写敏感。比如HelloWorld和Helloworld是不一样的。 包名 Package——公司、组织、个人的域名的反向,一般是英文字母。英文字母必须是小写。 类名(ClassName)采用大驼峰

【1.3 api服务网关(springcloudgateway)】基于springcloud gateway的webflux与google的kaptcha实现图形验证码功能_kaptcha和captchautil那个性能好-爱代码爱编程

一、背景 基于SpringCloud 微服务架构的项目中,需要使用图形验证码,以下是使用的记录。 二、验证码功能介绍 有两种工具生成验证码:Captcha 和 kaptcha 2.1 Captcha 介绍 2.1