java进阶(二)-java小干货

java一些精干知识点分享

  • 2. java小干货
    • 2.1循环遍历
    • 2.2可变参数
    • 2.3 list和数组转化
      • 2.3.1 数组转list
      • 2.3.2 list转数组
    • 2.4 值传递和地址传递
      • 2.4.1值传递
      • 2.4.2 地址传递
      • 2.4.3易错点总结
    • 2.5 数据类型
      • 2.5.1基础知识
      • 2.5.2 基础数据和包装类
    • 2.6 字符串
      • 2.6.1 char/String区别
      • 2.6.2 .关于String的创建方式
      • 2.6.3 String StringBuffer StringBuild区别
    • 2.7数组
      • 2.7.1 数组定义
      • 2.7.2 数组帮助类Arrays
      • 2.7.3 Apache Commons Lang3
    • 2.8 equals和==、compareTo区别
      • 2.8.1 ==和equals
      • 2.8.2 compareTo
    • 2.9代码块、内部类和匿名类
    • 2.5集合
    • 2.6文件流
    • 2.7代码块、内部类和匿名类
    • 2.8 java泛型及通配符
    • 2.9 日期类LocalDate
    • 2.10枚举
    • 2.11 java常见数据结构

2. java小干货

2.1循环遍历

数组、list、map都需要遍历循环,有下面集中循环方式
1.for ecah
list可以是一个数组、list、set

// list可以是一个数组、list、set
for(bject o :list) 
   {

   }

2.Iterator迭代器
list可以是list、set类的子类

Iterator iter = list.iterator();

   while(iter.hasNext()){

      Object o = iter.next();

   }

3.loop with size
可以是数组、list能得到索引长度的类及子类

for(int i=0;i<list.size();i++){

      Object o= list.get(i);

   }

4.lambda表达式

 list.forEach(
                (value)->{
                    System.out.println(value);
                }
        );

代码示例

public class GanHuo {
    @Test
    public void t1(){
        //1.for-each遍历,最简单,但无法获得索引
        System.out.println("=======for(Object:list)循环=========");
        String arrayStr[]=new String[]{"1","2","3"};
        //1-1 数组
        System.out.println("for-each遍历数组-----------");
        for (String s : arrayStr) {
            System.out.println("arrayStr:"+s);
        }
        //1-2 list
        List<Integer> list= Arrays.asList(1,2,3,4);
        System.out.println("for-each遍历list-----------");
        for (Integer i : list) {
            System.out.println("list:"+i);
        }

        //1-3 遍历map
        Map<String,String> map=new HashMap<>();
        System.out.println("for-each遍历Map-----------");
        map.put("1", "111");
        map.put("2", "222");
        map.put("3", "222");
        //得到key的collecton
        Set<String> keySet=map.keySet();
        for(String key:keySet){
            System.out.println("map["+key+"]="+map.get(key));
        }

    }

    @Test
    public void t2(){
        System.out.println("=======Iterator循环================");
        //1-2 list
        List<Integer> list= Arrays.asList(1,2,3,4);
        System.out.println("Iterator 遍历list-----------");
        Iterator iter=list.iterator();
        while (iter.hasNext()) {
            System.out.println("list:"+iter.next());
        }

        //1-3 遍历map
        Map<String,String> map=new HashMap<>();
        System.out.println("Iterator 遍历Map-----------");
        map.put("1", "111");
        map.put("2", "222");
        map.put("3", "222");
        //得到key的collecton
        Set<String> keySet=map.keySet();
        iter=keySet.iterator();
        while (iter.hasNext()) {
            String key= (String) iter.next();
            System.out.println("map["+key+"]="+map.get(key));
        }
    }

    @Test
    public void t3(){
        System.out.println("=======for。size循环================");
        //1-1 数组
        String arrayStr[]=new String[]{"1","2","3"};
        System.out.println("loop size 遍历数组-----------");
        for (int i = 0; i < arrayStr.length; i++) {
            System.out.println("arrayStr["+i+"]="+arrayStr[i]);
        }
        //1-2 list
        List<Integer> list= Arrays.asList(1,2,3,4);
        System.out.println("loop size 遍历list-----------");
        for (int i = 0; i < list.size(); i++) {
            System.out.println("list["+i+"]="+list.get(i));
        }


    }

    @Test
    public void t4(){
        System.out.println("=======lambda表达式================");
    
        //list的lambda表达式
        List<Integer> list= Arrays.asList(1,2,3,4);
        System.out.println("lambda表达式 遍历list-----------");
        list.forEach(
                (value)->{
                    System.out.println(value);
                }
        );

       //Map的lambda表达式
        Map<String,String> map=new HashMap<>();
        System.out.println("lambda表达式 遍历Map-----------");
        map.put("1", "111");
        map.put("2", "222");
        map.put("3", "222");

        map.forEach((key, value)->{
            System.out.print("key = " + key);
            System.out.println(", value = " + value);
        });
    }


}

2.2可变参数

可变参数是指不指定参数的个数

定义:
数据类型… 变量名
可变参数规范
1.可变参数本身是一个数组
2.可变参数也可传递一个数组
3.可变参数个数不受限制,可无限制,也可没有
4.如果可变参数和常规参数混合,则可变参数要放到最后
5.每个方法最多只能有一个可变参数
代码示例

public class ChangeParam {

    public void param(Integer... val){
        System.out.println("val包含:"+val.length+"个参数");
        for (Integer i : val) {
            System.out.println(i);
        }
    }

    /***
  如果一个方法里包含常规参数和可变参数,则可变参数必须放置到最后一个
     */
    public void param1(String name,Integer age,String... likes){
        System.out.println("name:"+name);
        System.out.println("age:"+age);
        System.out.println("likes-----");
        String temp="";
        for (String like : likes) {
            temp+=like+",";
        }
        System.out.println(temp);
    }



    @Test
    public void t1(){
        //可以传递不受限制的个数
        param(1,2,3);
        //可以不传参数
        param();
        //也可传递数组
        Integer[] array={1,2,3};
        param(array);
        //常规和可变参数混合
        param1("蒋增奎",20,"火锅","串串","烤鸭");
    }
}

2.3 list和数组转化

2.3.1 数组转list

1.使用List=Arrays.asList(数组对象),最简单,但不能新增删除
2.List=new ArrayList<>(Arrays.asList(intArray)),可新增删除,但性能差
3. Collections.addAll(list对象, 数组对象);可新增删除,性能好
4.list= Stream.of(数组对象).collect(Collectors.toList());

@Test
    public void array2List(){
        System.out.println("=========Arrays.asList=======");
        //1---直接用Arrays.asList后不能再新增
        System.out.println("1---直接用Arrays.asList后不能再新增");
        //基本类型数组
        Integer[] intArray={1,2,3};
        List<Object> list1= Arrays.asList(intArray);
       // list1.add(4);   //不能再新增,否则要报异常
        printList(list1);
        //自定义数组
        TestVO[] objArray={new TestVO(1,"jzk"),new TestVO(2,"张三")};
        list1=Arrays.asList(objArray);
        printList(list1);

        //2--Arrays.asList作为构造参数传入,可新增,但性能差
        System.out.println("2--Arrays.asList作为构造参数传入,可新增,但性能差");
         list1=new ArrayList<>(Arrays.asList(intArray));
        list1.add(4);
        printList(list1);

        //3--Collections.addAll(list,数组);能新增删除,性能好
        System.out.println("3--Collections.addAll(list,数组);能新增删除,性能好");
        list1=new ArrayList<>();
        Collections.addAll(list1, intArray);
        list1.add(4);
        printList(list1);

        //4--使用 Stream;能新增删除,性能好
        System.out.println("4--使用 Stream;能新增删除,性能好");
        list1= Stream.of(intArray).collect(Collectors.toList());
        list1.add(4);
        printList(list1);

    }

    private void printList(List<Object> list){
        for (Object o : list) {
            System.out.println(o);
        }
    }

2.3.2 list转数组

核心用到list.toArray()方法
1.Object[] arrays=list.toArray(); 只能获得Object数组
2.对象数组=list.toArray(new 对象[list.size] ) ;//可以获得对应的对象数组

测试代码


    @Test
    public void list2array(){
        List<TestVO> list=getTestVO();

        System.out.println("方法1:list.toArray()===========");
        //注意:只能用转换成Object[]数组,不能强制转化
        Object[] arrays=list.toArray();
        for (Object array : arrays) {
            System.out.println((TestVO)array);
        }
        System.out.println("方法2:list.toArray(数组对象)===========");
        //这样可获得实际的类
        TestVO[] vos=new TestVO[list.size()];
       list.toArray(vos );
        for (TestVO vo : vos) {
            System.out.println(vo);
        }
        //或者这样写
        System.out.println("方法3:list.toArray(数组对象)简写===========");
        vos=list.toArray(new TestVO[list.size()]);
        for (TestVO vo : vos) {
            System.out.println(vo);
        }

        System.out.println("方法4:String[] strings = list.stream().toArray(String[]::new);===");
        TestVO[] vos2=list.stream().toArray( TestVO[]::new);
        for (TestVO vo : vos2) {
            System.out.println(vo);
        }
    }

    private void printList(List<Object> list){
        for (Object o : list) {
            System.out.println(o);
        }
    }

    private List<TestVO> getTestVO(){
        List<TestVO> list=new ArrayList<>();
        list.add(new TestVO(1,"jzk"));
        list.add(new TestVO(2,"张三"));
        return list;

    }

2.4 值传递和地址传递

在学习 Java 编程语言的过程中,我们经常会听到“值传递”和“地址传递”这两个概念。它们是用来描述参数传递方式的术语,而理解它们的区别对于编写高效的代码非常重要。在本文中,我们将详细介绍这两种传递方式,并通过代码示例来说明它们的差异。

2.4.1值传递

在 Java 中,基本数据类型(如整数、布尔值等)都是以值传递的方式进行参数传递。这意味着当我们将一个基本数据类型作为参数传递给一个方法时,方法内部会创建一个新的变量来存储这个参数的值,而不会影响原始的变量。

执行过程

  • 首先,在调用方法时,将实际参数的值复制一份,并将这份副本传递给方法进行操作。
  • 在方法内部,这个副本的值被赋给一个新的局部变量。
  • 在方法执行过程中,对该局部变量的任何改动都不会影响原始的变量,因为它们指向的是不同的内存空间。
  • 当方法执行完毕后,这个局部变量和方法的栈帧都会被销毁,而原始的变量的值保持不变。

基本数据类型的传递过程中,传入的值被复制到方法内部,并在方法内部进行操作,但不会影响原始变量的值。

@Test
    public void valPass(){
        String str="a";
        double db= Double.parseDouble("34.5");
        Double db1=45.2;
        Integer zs=Integer.valueOf(100);
        int zs1=200;
        boolean b=false;
        Boolean b1= true;
        System.out.println("str="+str);
        System.out.println("db="+db);
        System.out.println("db1="+db1);
        System.out.println("zs="+zs);
        System.out.println("zs1="+zs1);
        System.out.println("b="+b);
        System.out.println("b1="+b1);
        change1(str,db,db1,zs,zs1);
        System.out.println("str="+str);
        System.out.println("db="+db);
        System.out.println("db1="+db1);
        System.out.println("zs="+zs);
        System.out.println("zs1="+zs1);

    }

    private void change1(String str,double db,Double db1,int zs,Integer zs1){
        System.out.println("============change==========");
        str="b";
        db=-45.2;
        db1=-22.4;
        zs=-1;
        zs1=-2;
    }

执行效果,可以看出这些都是值传递,被引用后并没有改变以前值:

str=a
db=34.5
db1=45.2
zs=100
zs1=200
b=false
b1=true
============change==========
str=a
db=34.5
db1=45.2
zs=100
zs1=200

2.4.2 地址传递

与基本数据类型不同,Java 中的对象类型(如数组、集合、自定义类等)则是以地址传递的方式进行参数传递。这意味着当我们将一个对象作为参数传递给一个方法时,方法内部使用的是这个对象的引用,而不是对象本身。

执行过程

  • 创建一个对象并将其引用赋值给一个变量。

  • 将这个变量作为参数传递给一个方法。

  • 在方法内部,参数变量接收到了对原始对象的引用。

  • 在方法内部修改参数变量所指向的对象时,原始对象也会受到影响。

  • 方法执行完毕后,返回到原始调用处,可以通过原始变量访问到被修改后的对象。

对象的引用传递意味着传递的是对象的引用,通过引用可以访问和修改原始对象的属性。

测试代码:

 @Test
    public void addressPass(){
        StringBuffer sb=new StringBuffer("aa");
        TestVO vo=new TestVO(1,"蒋增奎");
        String[] array={"1","2","3"};
        List<Integer> list=new ArrayList<>();
        list.add(1);list.add(2);
        Map<String,Integer> map=new HashMap<>();
        map.put("1", 11);
        map.put("2", 22);
        System.out.println("sb:"+sb);
        System.out.println("vo:"+vo);
        System.out.println("array:"+ Arrays.toString(array));
        System.out.println("list:"+Arrays.toString(list.toArray()));
        System.out.println("map:"+map.toString());


        System.out.println("================");
        change2(sb,vo,array,list,map);

        System.out.println("sb:"+sb);
        System.out.println("vo:"+vo);
        System.out.println("array:"+ Arrays.toString(array));
        System.out.println("list:"+Arrays.toString(list.toArray()));
        System.out.println("map:"+map.toString());


    }
    private  void change2( StringBuffer sb, TestVO vo,String[] array,
                           List<Integer> list,Map<String,Integer> map){
        sb.append("dd");
        vo.setName("蒋大爷");
        array[0]="改值11";
        list.add(3);
        map.put("3",333);
    }

效果,地址引用值都会被改变

sb:aa
vo:TestVO(id=1, name=蒋增奎)
array:[1, 2, 3]
list:[1, 2]
map:{1=11, 2=22}
================
sb:aadd
vo:TestVO(id=1, name=蒋大爷)
array:[改值11, 2, 3]
list:[1, 2, 3]
map:{1=11, 2=22, 3=333}

代码2:

  @Test
    public void t2() {
      TestVO vo1=new TestVO(1, "jzk");
      TestVO vo2=vo1;
      vo2.setName("奎哥");
      System.out.println(vo1); //打印TestVO(id=1, name=奎哥),不是jzk
      System.out.println(vo2);//TestVO(id=1, name=奎哥)
    }

首先创建一个对象TestVO vo1,接着申请另一款空间,用来创建TestVO vo2,且vo2=vo1,说明两个数组都指向同一块空间,修改vo2中的字段也就相当于修改了vo1中对应的元素。

代码3


    @Test
    public void t1(){
        TestVO vo=new TestVO(1, "jzk");
        System.out.println(vo);
        change3(vo);
        System.out.println(vo);
        change4(vo);
        System.out.println(vo);

    }
    private void change3(TestVO vo){
        TestVO vo1=vo;  //把vo赋值给vo1,两个对象是指向同一个地址
        vo1.setName("奎哥");
    }
    private void change4(TestVO vo){
        vo.setName("鸡哥");
    }

打印效果:

TestVO(id=1, name=jzk)
TestVO(id=1, name=奎哥)
TestVO(id=1, name=鸡哥)

代码说明:
change3()和change4()效果一样,change3()虽然通过了赋值,但两个对象指向的同一个地址

2.4.3易错点总结

易错点
java对象:String ,int等对应的封装类Integer,java.util.Date,BigDecimal是值传递,不是地址传递,虽然他们是对象

值传递VS地址传递

java进阶(二)-java小干货_第1张图片

2.5 数据类型

2.5.1基础知识

​ Java基本类型共有八种,基本类型可以分为三类,字符类型char,布尔类型boolean以及数值类型byte、short、int、long、float、double。数值类型又可以分为整数类型byte、short、int、long和浮点数类型float、double。JAVA中的数值类型不存在无符号的,它们的取值范围是固定的,不会随着机器硬件环境或者操作系统的改变而改变。实际上,JAVA中还存在另外一种基本类型void,它也有对应的包装类 java.lang.Void,不过我们无法直接对它们进行操作

java进阶(二)-java小干货_第2张图片

java进阶(二)-java小干货_第3张图片

代码说明

 //基础数据类型
    @Test
    public void t1(){
        //1.整数类型
        byte b=100;
        short s=10000;
        int  i=1000000000;
        //注意:长整型long要加L后缀,才能最大化
        long l=900000000000000000L;
        System.out.println("byte:"+b);
        System.out.println("short:"+s);
        System.out.println("int:"+i);
        System.out.println("long:"+l);

        //2.浮点型
        //注意:小数默认是double,如果要用float,需要再数字后面加f或者F
        float f=34.67f;
        double d=34.67;

        //char类型,char必须用单引号包围,只能一个字符
        char c1='A';
        char c2='2';

        //boolean
       boolean b1=false;
       
    }

注意事项:

1.整数:short int long 就是取值范围不一样,对计算没有影响,当然计算性能存储越低性能越高,long后面需要增加L/l后缀
2.浮点型:小数默认为double类型,float要加l/L后缀,double计算精度高,但性能差些,但高精度计算用BigDecmal(小数存在计算精度问题)
3.基础类型不能赋null,只有对应包装类才行

默认值和初始化
每一种类型都有一个默认值,除基本类型外,其他的类型的默认值都是 null,因为它们都是引用类型。整数默认为 int 类型,浮点数默认为 double 类型。
java进阶(二)-java小干货_第4张图片
代码

	public      float f;
    public      double d;
    public   boolean b;
    private  int i;
    private  Boolean b3;
    @Test
    public void t2(){
      //静态方法有默认值
        System.out.println(f);  //0
        System.out.println(d);  //0
        System.out.println(i);  //0
        System.out.println(b); //false
        System.out.println(b3); //null
        boolean b1;
        System.out.println(b1); //编译不通过

    }

注意事项:

1.只有为class的字段属性声明才有默认值
2.在方法内声明的变量,如果不赋初始值,编译不通过

2.5.2 基础数据和包装类

​ Java 是面向对象的语言,但是为了便于开发者的使用,Java 中却沿用了 C 语言的基本数据类型,在进行基本的数据计算时,开发者可以直接使用基础类。但是基本数据类型是不具备对象的特征的,不能调用方法,而且基本数据类型不能存入集合中,所以就需要将基础数据类型实例封装为 Java 对象,使其具有了对象的属性和方法。
java进阶(二)-java小干货_第5张图片

基础类型和包装类的区别

  • 存储位置不同:
    基本数据类型直接将值放在栈中;
    包装类型是把对象放在堆中,然后通过对象的引用来调用他们 ;

  • 初始值不同:
    int的初始值为 0 、 boolean的初始值为false ;
    包装类型的初始值为null ;

  • 使用方式不同:
    基本数据类型直接赋值使用就好;
    在集合如 coolectionMap 中只能使用包装类型;
    在应用场景中MVC模式的form-vo,Dto,PO对象的属性最好都用包装类,因为基础类型都有默认值0或者false,在实际应用中,null和0,false是有实际意义的

  • 包装类是java对象,封装有相关方法,而基础类型没有
    比如:Integer.valueOf()等

为什么还要保留基础类型?

  • 在 Java 中,使用 new 关键字创建的对象存储在堆中,并且通过栈中的引用来使用这些对象,所以对象本身来说是比较消耗资源的。
  • 基本类型存储在栈里,因为栈的效率高,所以保留了基本类型。变量的值存储在栈中,方法执行时创建,结束时销毁,因此更加高效。
  • 使用基本数据类型参与计算时的性能要比使用包装类的高。

基础类型之间的转换
(1)基础类型自动转化

1.范围小的类型可以自动转换成范围大的类型。
2.整型可以自动转换成浮点型
3.反之,范围大的转化为范围小的必须强制转换
4.范围:short->int->long->float->double ,从小到大

示例代码:

 @Test
    public void t3(){
        System.out.println("1.自动转换===========");
        byte i1=2;
        short i2=i1;
        int i3=i2;
        long i4=i3;

        float f1=3.45f;
        double f2=f1;
        float f3=i3;
        double f4=i4;

    }

(2)强制执行

范围大的转化为范围小的,必须用强制转换
范围大的类型需要强制转换成范围小的类型,否则会精度丢失。
强制类型转换可能会导致数据溢出或者产生负数。
范围小到范围大的的转换也可以用强制转化,和自动转换效果一样

 @Test
    public void t4(){
        System.out.println("2.强制转换===========");
        double f1=34.56565;
        float   f2=(float) f1;
         int i=(int)f1;
        System.out.println(i);
         //范围小的转换也可以用强制转化,和自动转换效果一样
         int  i1=34;
         float f3=(float)i1; 
       
    }

基本类型和包装类的转换
基本类型与包装类之间的转换需要使用到自动装箱和拆箱的操作。

 @Test
    public void t5(){

     System.out.println("3.基本类型和封装类转换===========");
     int i=10;
     Integer i1=i;  //自动装箱

     Integer i2=30;
     int i3=i2;//自动拆箱
    }

包装类的常用方法

1.包装类对象=包装类.valueOf(对应的基础类型);
2.基础数据类型/包装类对象=包装类.parseXXX(字符串) ;字符串转化成数据类型

@Test
    public void t6() {
        System.out.println("4.包装类的常用方法===========");
        Integer i = Integer.valueOf(2);
        int i1 = Integer.parseInt("344"); //字符串转成整数
        Integer i2 = Integer.parseInt("34444"); //实际是转化成int,int在装箱成Integer

        System.out.println(i);
        System.out.println(i1);
        System.out.println(i2);
    }

2.6 字符串

2.6.1 char/String区别

1.char和String的区别
char是字符类型,是基础数据类型,长度固定,用单引号表示 如 c=‘谢’;
String是字符串类型,不是基础数据类型,长度无法确定,用双引号表示 str=“傻啊”。
关于String类。
(1)、String类时final类,所以是不可继承的
( 2)、String类是的本质是字符数组char[];
( 3)、Java运行时会维护一个String Pool(String池),JavaDoc翻译很模糊“字符串缓冲区”。String池用来存放运行时中产 生的各种字符串,并且池中的字符串的内容不重复。而一般对象不存在这个缓冲池,并且创建的对象仅仅存在于方法的堆 栈区。
4.String虽然是对象,但传参也是值传递,不是地址传递

 @Test
    public void t7() {
        String s="abc";
        Character c='中';
       char[] cs= s.toCharArray();
        for (char c1 : cs) {
            System.out.println(c1);
        }
        char[] cs2={'天','地','人'};
        String s1=new String(cs2);
        System.out.println(s1);


    }

2.6.2 .关于String的创建方式

字符串有两种创建方式,String s1=“a”; String s=new String(“a”)其逻辑是不一样的

1.直接创建 String str1 = “123”
直接创建的 String 类的数据存储在公共的常量池中(Java 的常量优化机制),即直接创建的相同值的不同 String 类的引用相同。
2.new 创建 String str1 =new String(“123”)
通过 new 关键字创建的 String 和其他一般的类的创建一样,数据是存储在 String 类的对象的堆上,即通过 new 关键字创建的相同值的不同 String 类的引用不同。

String str1 = "Java";
String str2 = "Java";
String str3 = str2 + "";
String str4=new String("Java");
String str5=new String("Java");
String str6=str1;
String str7=str4
System.out.println(str1 == str2); // Output: true
System.out.println(str2 == str3); // Output: false
System.out.println(str4== str5); // Output: false
System.out.println(str1== str5); // Output: false
System.out.println(str1== str6); // Output: true
System.out.println(str4== str7); // Output: true

java进阶(二)-java小干货_第6张图片

代码说明:

  • (str1 == str2)== true
    直接创建String,其实就是放到常量池里的对象,直接创建时,先去常量池寻找,如果有,则引用,所以这两个时一个东西

  • (str2 == str3)==false
    str3 = str2 + “”;代码实际上是创建了一个StringBuild对象,已经是两个对象了

  • (str4 == str4)==false
    两个字符串都是new String(“Java”),是两个对象,所以为false

2.6.3 String StringBuffer StringBuild区别

1.字符串String
字符串类是final修饰,不可继承和修改的,

String s="a";
s=s+"b";

其实是产生了两个字符串,执行s=s+“b”;后,s="a"就被丢弃在公共常量池里,如果进行大量的修改,
会导致性能很差。
2.字符串StringBuffer
在 Java1.0 的时候,若要对字符串进行大量修改,应当使用 StringBuffer,它是可修改的,同时,当时的开发人员考虑到多个线程对一个字符串的修改可能出现线程不安全的问题,于是让 StringBuffer 在拥有可修改字符串的功能的情况下,又给它加上了线程安全的机制。看到这里是不是觉得还挺好,挺正常的?但是要知道一个前提,那就是在 Java5 之前的 Java 在处理字符串的速度上一直被别人诟病,原因出在哪里?原因就在于这个 StringBuffer 上面。

StringBuffer 本来是为了实现大量修改字符串的功能而出现的,但却因为 Java 的开发人员给它加了个线程安全的功能,导致它执行效率极大地下降。这个线程安全的功能的实现并不是像我们现在用的方法,当时只是保证没有异常抛出,程序可以正常运行下去而已。在 Java 中,要实现字符串的相加,用加法运算符将两个字符串相加即可。但在这个过程中,Java5 之前是有 String 自动隐含地转换成 StringBuffer,再进行操作这一个步骤的(毕竟 String 类不可直接修改)。只要有这些步骤,就可以实现字符串的修改,但是呢,StringBuffer 有个线程安全的功能,它会在上面提到的步骤中还额外的执行一些功能,以保证线程的安全,而且,这里实现线程安全的方式和我们现在用锁的方式是不一样的!它这里的实现线程安全的方式极为繁琐且复杂,这就大大降低了 StringBuffer 的执行效率,以至于后来被广大程序员诟病。
3.字符串StringBuilder
我们仔细地想一下,实际上也并没有多少地方需要在修改字符串的同时保证线程安全,就算有,我们给它加个锁就行。基于这种想法,在 StringBuffer 出现 10 年之后,Java 的开发人员回过头看这个问题,才发现 StringBuffer 的实现是多么的愚蠢,于是后来在 Java5 就有了 StringBuilder。StringBuilder 同样可以快速高效地修改字符串,同时不是线程安全的。虽然它不是线程安全的,但是它的执行效率却比 StringBuffer 要高上了不少。在 Java5 之后的版本中,字符串相加隐含的转化过程中,不再将 String 转化为 StringBuffer,而是转化成 StringBuilder。

总结:
在大量操作字符串时,java已经优化了,不推荐使用StringBuffer

2.7数组

2.7.1 数组定义

数组有多种定义方式

 @Test
    public void t1() {
        //第一种定义数组的方法:
        int[] array1 = {1, 2, 3};//直接赋值(静态初始化)
        //int[]是数组的类型,array为数组名,随意取名字

        //第二种定义数组的方法:
        int[] array2 = new int[]{1, 2, 3, 4};//数组的动态初始化


        //第三种定义数组的方法:
        int[] array3 = new int[10];//只是分配了内存,但是没有进行赋值,默认值都是0,
        System.out.println(array3[2]); //0

        //第四种定义数组的方法:
        int[] array4;
        array4 = new int[]{1, 2, 3};//一定要为数组符初值,不然编译器会报错,

        int[] array5=null;//等价int[] array4

    }

4.注意事项

  • 静态初始化虽然没有指定数组的长度,编译器在编译时会根据{}中元素个数来确定数组的长度。
  • 静态初始化时, {}中数据类型必须与[]前数据类型一致。
  • 静态初始化可以简写,省去后面的new T[]。T可以为任意数据类型。
  • 如果数组中存储元素类型为引用类型,默认值为null。
  • 初始化后,数组的长度是固定的,不能动态扩容,这个是和list最大的区别
  • 数组参数是地址引用,不是值引用

地址引用:

int[] array1 = {1,2,3,4};
System.out.print(Arrays.toString(array1));//打印[1,2,3,4]

int[] array2 = array1;
array2[1] = 99;
System.out.print(Arrays.toString(array1));//打印[1,99,3,4],不是[1,2,3,4]
System.out.print(Arrays.toString(array2));//打印[1,99,3,4]

首先创建一个数组array1,并初始化赋值为1,2,3,4,然后打印数组array1,接着申请另一款空间,用来创建array2,且array2=array1,说明两个数组都指向同一块空间,修改array2中的第二个元素也就相当于修改了array1中对应的元素。

2.7.2 数组帮助类Arrays

Arrays提供了几个很有用的数组帮助方法:

方法 说明
toString 把数组转化为字符串
sort 数组元素排序
binarySearch 查找元素在数组中的位置索引
asList 把数组转化成list

直接看代码,一目了然

 @Test
    public void t3(){
        System.out.println("Arrays类的常见用法");
        int[] array={5,4,2,6,3};
        //1.打印
        String str=Arrays.toString(array);
        System.out.println(str);//[5, 4, 2, 6, 3]
        //2.数组大小排序
        Arrays.sort(array);
        System.out.println(Arrays.toString(array));//[2, 3, 4, 5, 6]
        //3.判断两个数组内容是否相等
        int[] array1={1,2,3};
        int[] array2={1,2,3};
        System.out.println(Arrays.equals(array1, array2)); //true

        System.out.println(array1.equals(array2));//false,不能采用这个方法判断数组内容

        //3.查找某个元素的索引
        int[] array3={1,2,3};
        int index=Arrays.binarySearch(array3,2);
        System.out.println(index);  //1
        //注意事项,如果没有,则返回小于0,如果多个,则返回第一个
        int[] array4={1,2,3,2};
        System.out.println(Arrays.binarySearch(array4, 2));//1
        System.out.println("ddd:"+Arrays.binarySearch(array4, 4));//小于零
        //4.转化成list数据类型
        Integer[] array5={1,2,3};
        //如果是对象,则直接List<对应的数组元素类型>
        List<Integer> list=Arrays.asList(array5);
        for (Integer i : list) {
            System.out.println(i);
        }
      //     list.add(9); //运行报错,不能新增和删除
     //   list.remove(0);//运行报错,不能新增和删除

        /***
         注意如果数组是基本数据类型,用Array.asList是无法转化的。
         需要借助第三方先把基本类型数组转化成对应的包装类数组
         如:Apache Commons Lang3
         */
        int[] array6={1,2,3,5};
       Integer[] array7= ArrayUtils.toObject(array6);

     //4.copy值

        int[] arr1 = {1, 2, 3};
        int[] arr2 = Arrays.copyOf(arr1, 5);
        System.out.println(Arrays.toString(arr2)); //[1, 2, 3, 0, 0]
        //注意:copyOf是值copy,不是地址引用
        arr2[3]=20;
        System.out.println(Arrays.toString(arr2));//[1, 2, 3, 20, 0]
        System.out.println(Arrays.toString(arr1));//[1, 2, 3]
        //copyOfRange方法提供了开始索引
        int[] arr3 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        int[] arr4 = new int[5];
        arr4 = Arrays.copyOfRange(arr3,3,5);
        System.out.println(Arrays.toString(arr4));//[4, 5]

    }

2.7.3 Apache Commons Lang3

org.apache.commons.lang3.ArrayUtils这个类也很大扩展了数组的操作,具体查看apache文档

2.8 equals和==、compareTo区别

2.8.1 ==和equals

  • == 是一个运算符,用于比较两个对象的引用是否相同,即它们是否指向内存中的相同位置。
  • equals 是一个方法,通常在Object类中定义,它用于比较两个对象的内容是否相等。默认情况下,equals方法执行与==相同的引用比较,但它可以被子类重写以提供自定义的相等性逻辑

“== ”在哪些情况下比较的是对象内容而不是引用

  • 在Java中,== 运算符通常比较的是对象的引用。但在以下情况下,== 可以比较对象的内容而不是引用:
  • 对于基本数据类型(如int、char等),== 比较的是它们的值,而不是引用。
  • 字符串常量池:对于字符串字面值,就是String s=“123”,不是String s=new String(“123”);,Java使用常量池来存储它们,因此相同的字符串字面值使用==比较通常会返回true。

代码1

@Test
    public void t1(){
        //基本类型数据(数值、字符、布尔)的值一样,则==为true
        char c1='a';
        char c2='a';

        float f1=3.5f;
        float f2=3.5f;
        double f3=3.5;

        int i1=1;
        int i2=1;
        long i3=1l;

        System.out.println(c1==c2);//true
        System.out.println(f1==f2);//true
        System.out.println(f1==f3);//true
        System.out.println(i1==i2);//true
        System.out.println(i1==i3);//true

    }

代码2: 字符串是一个对象又有基础数据的特殊性,可参考2.6.2

@Test
    public void t2(){
        String s1="123";
        String s2="123";
        String s3=s1;
        String s4=s2+"";
        String s5=new String("123");
        String s6=new String("123");
        String s7=s5;
        //s="xx"是直接声明,String是final常量,性质和基础数据类型一样,s1,s2都指向同一个内存地址
        System.out.println(s1==s2); //true
        //所有=变量赋值的语法,指针都是一样
        System.out.println(s1==s3); //true
        //因为String是final类型,s2+""实际是创建一个对象
        System.out.println(s1==s4); //false
        //两个不同对象,内存地址不一样
        System.out.println(s5==s6); //false
        //所有=变量赋值的语法,指针都是一样
        System.out.println(s5==s7); //true

        //如果是euqal比较,这几个都返回true
        System.out.println(  //true
                s1.equals(s2) && s1.equals(s3) && s1.equals(s4) && s5.equals(s6)

        );

    }
}

代码3:标准vo对象

@Test
    public void t3(){
        TestVO vo1=new TestVO(1,"jzk");
        TestVO vo2=vo1;
        TestVO vo3=new TestVO(1,"jzk");

       //内存指针一样
        System.out.println(vo1==vo2);//true
        //两个不同对象
        System.out.println(vo1==vo3);//false

        //三个对象值都是一样的
        System.out.println(vo1.equals(vo2) && vo2.equals(vo3));//true

        //vo2修改了值,因为vo1指针和他一致,所以vo1也会改变,最后他们都是一致的
        vo2.setName("奎哥");
        System.out.println(vo1==vo2);//true

        //值已经改变了
        System.out.println(vo3.equals(vo1));//false

    }

equals 和 hashCode 之间有什么关系?

equals 和 hashCode 在Java中通常一起使用,以维护对象在散列集合(如HashMap和HashSet)中的正确行为。
如果两个对象相等(根据equals方法的定义),那么它们的hashCode值应该相同。
也就是说,如果重写了一个类的equals方法,通常也需要重写hashCode方法,以便它们保持一致。
这是因为散列集合使用对象的hashCode值来确定它们在内部存储结构中的位置。

2.8.2 compareTo

obj.compareTo(object otherstr);

仅仅知道两个字符串是否相同是不够的。对于排序应用来说,必须知道一个字符串是大于、等于还是小于另一个。一个字符串小于另一个指的是它在字典中先出现。而一个字符串大于另一个指的是它在字典中后出现。字符串(String)的 compareTo() 方法实现了这种功能。

  • compareTo() 方法用于按字典顺序比较两个字符串的大小,该比较是基于字符串各个字符的 Unicode 值。
  • 如果两个字符串调用 equals() 方法返回 true,那么调用 compareTo() 方法会返回 0,如果前者大则大于0,否则小于0
  • compareTo只能用于对象,不能用于基础数据类型,他实际上是Comparable接口类的方法,实现这个接口的有:String、基础数据类型的包装类、Date、BigDecimal 等

代码:

  @Test
    public void t4(){
        //字符串比较
        String s1="a";
        String s2="abc";
        System.out.println(s1.compareTo(s2));
        //基本类型的包装类比较
        Integer i1=3;
        Integer i2=5;
        System.out.println(i1.compareTo(i2));//<0
        System.out.println(i1<i2);//true

        //日期Date,BigDecimal
        Date d1= DateUtil.getDateByStr("2003-10-01", DateUtil.date_gs);
        Date d2= DateUtil.getDateByStr("2004-09-01", DateUtil.date_gs);
        System.out.println(d1.compareTo(d2));//<0

        BigDecimal bg1=new BigDecimal("1.0");
        BigDecimal bg2=new BigDecimal("1.00");
        System.out.println(bg1.equals(bg2)); //返回的是false,所以比较BigDecimal不要用equals
        System.out.println(bg1.compareTo(bg2));//0
        

    }
}

2.9代码块、内部类和匿名类

2.5集合

2.6文件流

2.7代码块、内部类和匿名类

2.8 java泛型及通配符

2.9 日期类LocalDate

2.10枚举

2.11 java常见数据结构

你可能感兴趣的:(j2se高级特性,java,windows,python)