Java学习笔记:进阶语法

本文深入探讨了Java的进阶语法,包括对象内存管理,涉及堆、垃圾回收机制、栈和方法区的详细解释。讲解了如何使用System.gc()方法建议垃圾回收,并分析了局部变量和成员变量的生命周期。此外,文章还涵盖了Debug调试技巧,API文档的使用,以及字符串String类的特性和方法,如String不可变性、字符串拼接的性能问题和StringBuilder类的使用。正则表达式的基础知识,如matches、split和replaceAll方法的应用也被提及。此外,还讨论了Object类的toString和equal方法,以及包装类的作用和转换方式。最后,介绍了File类的操作,如创建、删除文件和目录,以及使用FileFilter进行文件过滤。
摘要由CSDN通过智能技术生成

一、对象内存管理:
  • 编译好的Java程序需要运行在JVM中。
  • 程序,无论是代码还是数据,都需要存储在内存中。JVM为Java程序提供并管理所需要的内存空间。
  • JVM内存分为“堆”、“栈”和“方法区”三个区域,分别用于存储不同的数据。

demo

①堆内存:
  • JVM在其内存空间开辟了一个称为“”的存储空间;
  • 这部分空间用于存储使用使用new关键字所创建的对象

demo

  • 成员变量的生命周期:
    • 访问对象需要依靠引用变量。
    • 当一个对象没有任何引用时,会被GC(垃圾回收器)进行回收,该对象中的所有成员变量也随之被回收。
    • 成员变量的生命周期为:从对象在堆中创建开始到对象被GC回收结束
②垃圾回收机制:
  • 垃圾回收器(Garbage Collection,简称GC)是JVM自带的一个线程(自动运行着的程序),用于回收没有任何引用指向的对象。

  • Java程序员不用担心内存管理,因为垃圾回收器会自动进行内存回首。

  • Java程序的内存泄漏问题

    • 内存泄漏是指——不再使用的内存没有被及时的回收。严重的内存泄漏会因为过多的内存被占用而导致程序的崩溃。
    • GC线程判断对象是否可以回收的依据是该对象是否有引用指向,因此,当确定该对象不再使用时,应该及时将其引用设置为null.
  • System.gc()方法

    • GC的回收对于程序员来说是不可见的,并不一定一发现有无引用的对象就立即回收。
    • 一般情况下,当我们需要GC线程即刻回收无用对象时,我们可以调用System.gc()方法。
    • System.gc()方法用于建议(不一定执行)虚拟机马上调度GC线程回收资源,具体的实现策略取决于不同的JVM系统。

③栈:
  • 栈用于存放方法中声明的所有局部变量

demo

package MyTest;

public class Test{
   
    int a;
    public static void main(String[] args) {
   
        Test t = new Test();
        t.show(2);
    }
    public void show(int b){
   
        int c;
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
    }
}
//error:Variable 'c' might not have been initialized
  • 分析:一个变量在使用之前必须提前声明并且初始化,对于上面中的实例变量a,会自动初始化为0,所以不用担心;对于变量b,在调用相关函数show时,一定会传入一个参数用于变量b的初始化,所以也不用担心;但是对于变量c来说,仅仅对其进行了声明,并未对其初始化,所以会报错!

  • 局部变量的生命周期

    • 一个运行的Java程序从开始到结束会有多次方法的调用。JVM会为每一个方法的调用在栈中分配一个对应的空间,这个空间我们称之为该方法的栈帧
    • 一个栈帧对应一个正在调用中的方法,栈帧中存储了该方法的参数、局部变量等数据。当某一个方法调用完成之后,其对应的栈帧将会被清除,局部变量失效
  • 成员变量与局部变量

    • 局部变量:
      • 定义在方法中。
      • 没有默认值,必须自己设定初始值。
      • 方法被调用时,存在栈中,方法调用结束,从栈中清除。
    • 成员变量:
      • 定义在类中,方法外。
      • 有初始默认值,可以不显式初始化。
      • 所有类在被实例化后,存在堆中,对象回收时,成员变量失效。
④方法区:
  • 方法区用于存放类的信息
    • Java程序运行时,首先会通过类装载器载入类文件的字节码信息,经过解析后将其装入方法区,==类的各种信息(包括方法)==都在方法区中存储。

demo

  • 方法只有一份
    • 当类的信息被加载到方法区时,除了类的类型信息之外,同时在类内的方法定义也被加载到方法区。
    • 类在实例化对象时,多个对象会拥有各自在堆中的空间,但是所有实例化对象是共用在方法区中的一份方法定义的

二、Debug调试:
  • 主要使用四个按键
功能 Eclipse Idea
单步调试,进入到方法中。 F5 F7
单步调试,不会进入到方法中。 F6 F8
结束方法的调试,返回。 F7 shift+F8
直接跳到下一个断点,若无断点则调试结束。 F8 shift+F8
  • 主要观看两个窗口:

image-20210716223801721

Variables窗口:用于观看相关变量的值。

Watchers窗口:用于添加相关的逻辑表达式,用于判断真假。


三、API文档:
①JDK API:
  • 什么是JDK API?

    • JDK中包含大量的API类库,所谓的API(应用程序编程接口)就是一些已写好、可供直接调用的功能(在java中这些功能以类的形式封装)。
    • JDK API包含的类库功能强大,经常使用的有:字符串操作、集合操作、文件操作、输入输出操作、网络操作、多线程等。
  • JDK包结构

    • 为了便于使用和维护,JDK类库按照包结构划分,不同功能的类划分在不同的包中。

    • 经常使用的包有:

      功能
      java.lang Java程序的基础类,如字符串、多线程等,该包中的类的使用频率非常的高,不需要import,可以直接使用。
      java.util 常用工具类,如集合、随机数产生器、日历、时钟等
      java.io 文件操作、输入/输出操作
      java.net 网络操作
      java.math 数学运算相关操作
      java.security 安全相关操作
      java.sql 数据库访问
      java.net 处理文字、日期、数字、信息的格式
②文件注释规范:

文档注释主要只在三个地方出现:类上面、方法上面、变量上面

/**
 * 这是用于测试功能的一个测试用例!  //类功能说明
 * @author YiWen Wan           //作者
 * @version 1.204,06/09/06     //版本
 * @see java.lang.StringBuffer //参见
 * @since JDK 1.0              //始于JDK版本
 * ……
 */
  • 实际使用样例
package MyTest;

/**
 * 这是用于测试功能的一个测试用例!  //类功能说明
 * @author YiWen Wan           //作者
 * @version 1.204,06/09/06     //版本
 * @see java.lang.StringBuffer //参见
 * @since JDK 1.0              //始于JDK版本
 */
public class Test {
   
    /**
     * 用于输出提示性话语的一个String变量!
     */
    public static String string = "Hello World!";
    /**
     * 主函数
     * @param args
     */
    public static void main(String[] args) {
   
        int a = 7;
        int b = 8;
        System.out.println(string);
        Plus(a,b);
    }

    /**
     * 用于计算两数加法运算,并限制其输出的一个函数。
     * @param num1:参与加法运算的其中一个参数
     * @param num2:参与加法运算的另一参数
     */
    public static void Plus(int num1,int num2){
   
        int num=-1;
        num = num1 + num2;
        if (num>=10){
   
            System.out.println(num);
        }
    }
}
③导出项目的JavaDoc文档:

image-20210722104147774

  • 下一步

    image-20210722105223651

    -encoding utf-8 -charset utf-8
    
    • 这里有的教程会让你写:
    -encoding UTF-8 -charset UTF-8 -windowtitle "你的文档在浏览器窗口标题栏显示的内容" -link http://docs.Oracle.com/javase/7/docs/api
    

    两者的区别就在于,有没有和java官方的文档“联动起来”。

    • 第一种:

    image-20210722105818069

    • 第二种:

    image-20210722105947369

    当你点击java语言中已存在的类时,他会跳转到官方文档!

    image-20210722110145346


四、字符串String类:
①String是不变对象:
  • java.lang.String使用了final进行修饰,所以不能被继承
  • 字符串底层封装了字符数组以及针对字符数组的操作算法。
  • 字符串一旦创建,对象就永运无法改变,但是字符串引用可以重新赋值
  • Java字符串在内存中采用了Unicode编码方式,任何一个字符对应着两个字节的定长编码。
  • String基本使用特性进行代码验证
/**
 * String是不变对象,JVM对其做了一个优化,在内存中开辟了一段区域作为常量池,
 * 凡是通过“字面量”(直接量)形式创建的字符串对象都会缓存并且重用。因为会重用
 * 对象,所以该对象内容不可以改变!
 * @author YiWen Wan
 */
public class StringDemo {
   
    public static void main(String[] args) {
   
        String str1 = "Hello World!";
        String str2 = "Hello World!";
        System.out.println("Java重用了这一个字符串直接量!true or false?");
        //直接比较引用是否相等,来进一步说明是否指向了同一片内存区域!
        System.out.println(str1==str2);
    }
}
//Java重用了这一个字符串直接量!true or false?
//true
  • String不变对象的特性进行代码验证
/**
 * 一个有趣的现象!
 * 因为对象的内容是不可变的,所以修改原指向的值本质上是重新创建了一个新的字符串,
 * 原字符串还保留着,防止引起原同一引用的值发生改变!
 * @author YiWen Wan
 */
public class StringDemo {
   
    public static void main(String[] args) {
   
        String str1 = "Hello";
       String str2 = "Hello";
        //原本str1和str2是指向同一块内存区域的,现在改变str1的值!
        str1 = str1+"!";
        System.out.println(str1);
        System.out.println(str2);

    }
}
//Hello!
//Hello
  • 当使用new语句创建String对象时,无论内容是否相等,都会强制创建一个新的对象!
/**
 * 使用new创建新的String对象时,无论之前是否有一样内容的String对象,
 * 都会强制创建一个新的对象!
 * @author YiWen Wan
 */
public class StringDemo {
   
    public static void main(String[] args) {
   
        String str1 = "Hello";
        String str2 = "Hello";
        String str3 = new String("Hello");
        System.out.println(str1==str2);
        System.out.println(str1==str3);
        System.out.println("分割线:--------------");
        System.out.println(str1.equals(str3));
    }
}
//true
//false
//true
  • 所以当比较两个String类型的对象是否相等时,利用equal函数进行判断更为准确,因为不是指向同一对象的String引用也可能内容相等!

  • 对String对象进行拼接之后产生的新对象的特性

/**
 * 测试分割重组的String对象的一些特性!
 * @author YiWen Wan
 */
public class StringDemo {
   
    public static void main(String[] args) {
   
        String str1 = "HelloWorld";

        /*这里是一个编译器的一个优化措施,编译器在编译源代码时,发现计算表达式的所有参数都是“字面量”,在编译之后就直接会将这些“字面量”直接计算了,并将结果编译到class文件中,所以在执行该条语句的时候相当于:
                    String str2 = "HelloWorld";
        所以后续输出才会是true,这已经不是String的特性了!
         */
        String str2 = "Hello" + "World";
        System.out.println(str1==str2);

        //计算表达式有一方是变量时,就一定会创建一个新的对象,所以才会输出false!
        String s = "Hello";
        String str3 = s + "World";
        System.out.println(str1==str3);

    }
}
//true
//false
②修改字符串的性能问题:
  • 当字符串频繁进行修改时
    • 此时就会频繁的新建字符串,效率就会大幅度降低,内存使用不高效,性能降低,垃圾回收器来不及收
/**
 * 用于测试String中函数特性!
 * @author YiWen Wan
 */
public class StringTest {
   
    public static void main(String[] args) {
   
        String str = "a";
        for (int i=0;i<100000000;i++)
            str = str + "a";
        System.out.println("Game Over!");
    }
}
//结果出不来,一直卡着!
  • 所以Java中String是不变对象,目的就是提高了重用性,但是对于频繁修改String对象就考虑的不是很完备,“一刀切”思想!

  • StringBuilder类

    • 为了针对修改字符串的情况,Java提供了StringBuilder类(增、删、改、插)进行处理!
    • StringBuilder封装可变的字符串,对象创建之后可以通过调用方法改变其封装的字符序列。
/**
 * 用于测试StringBuilder中函数特性!
 * @author YiWen Wan
 */
public class StringTest {
   
    public static void main(String[] args) {
   
       String str = "好好学习 ";

       //当使用无参数的构造方法时,默认生成的是一个空字符串,可以用来以后加东西!
       StringBuilder sb = new StringBuilder();
       StringBuilder stringBuilder = new StringBuilder(str);

       //①增——append()函数,拼接字符串!
        System.out.println(stringBuilder.append("天天向上!").toString());
       //②改——replace()函数,用于替代指定范围内的字符串内容!表示范围时注意含头不含尾!
        System.out.println(stringBuilder.replace(8,9,"后").toString());
       //③删——delete()函数,用于删除指定位置的字符串内容!表示范围时注意含头不含尾!
        System.out.println(stringBuilder.delete(0,5).toString());
       //④插——insert()函数,用于将指定字符串插入到原字符串指定的范围内!
        System.out.println(stringBuilder.insert(2,"向上、向下、向左、向右、向前、"));
        System.out.println(stringBuilder.reverse());//反转
    }
}
//        好好学习 天天向上!
//        好好学习 天天向后!
//        天天向后!
//        天天向上、向下、向左、向右、向前、向后!
  • 针对上上面代码的改进版:
/**
 * 用于测试StringBuilder中函数特性!
 * @author YiWen Wan
 */
public class StringTest {
   
    public static void main(String[] args) {
   
        StringBuilder stringBuilder = new StringBuilder("a");
        for (int i=0;i<10000000;i++)
            stringBuilder.append("a");
        System.out.println("Game Over!");
    }
}
//    Game Over!
  • StringBuilder总结
    • Java中字符串的连接过程就是利用StringBuilder实现的。

      • String str = “Hello”; String str1 = str+" World!";
      • 实际上:String str1 = new StringBuilder(str).append(" World!");
    • StringBuilder与StringBuffer

      • StringBuffer是线程安全的,同步处理的,性能稍慢。
      • StringBuilder是线程非安全的,并发处理的,性能稍快。
③String类中的常用函数:
  • indexof函数:
    • 返回给定字符串位于当前字符串的位置(首位置),如果找不到则返回-1。
/**
 * 用于测试String中函数特性!
 * @author YiWen Wan
 */
public class StringTest {
   
    public static void main(String[] args) {
   
        String str = "HelloWorld!";
        System.out.println("Length:"+str.length());
        System.out.println("位置是:"+str.indexOf("Hello"));
        System.out.println("位置是:"+str.indexOf("WYW"));
        
        //验证一下indexof的其他重载函数!
        System.out.println("位置是:"+str.indexOf("o"));
        //从指定位置开始查找:
        System.out.println("位置是:"+str.indexOf("o",5));
        //查找最后一次出现的位置:
        System.out.println("位置是:"+str.lastIndexOf("o"));
    }
}
//        Length:11
//        位置是:0
//        位置是:-1
//        位置是:4
//        位置是:6
//        位置是:6
  • substring函数:
    • 截取指定范围内的字符串。
    • 注意:Java API有一个特点——通常使用两个数字表示的范围都是 “含头不含尾” 的!
/**
 * 用于测试String中函数特性!
 * @author YiWen Wan
 */
public class StringTest {
   
    public static void main(String[] args) {
   
        String str = "HelloWorld";
        System.out.println("截取的字符串为:"+str.substring(0,5));
        //当参数变成一个的时候,就变成了一刀切了!
        System.out.println("截取的字符串为:"+str.substring(5));
    }
}
//截取的字符串为:Hello
//截取的字符串为:World
  • trim函数:
    • 去掉字符串的前后的空格
/**
 * 用于测试String中函数特性!
 * @author YiWen Wan
 */
public class StringTest {
   
    public static void main(String[] args) {
   
        String str = "     HelloWorld!     ";
        System.out.println("去掉之前的效果是:"+str);
        System.out.println("去掉之后的效果是:"+str.trim());
    }
}
//        去掉之前的效果是:     HelloWorld!
//        去掉之后的效果是:HelloWorld!
  • charAt函数:
    • 返回字符串指定位置的字符。
/**
 * 用于测试String中函数特性!
 * @author YiWen Wan
 */
public class StringTest {
   
    public static void main(String[] args) {
   
        String str = "HelloWorld";
        System.out.println("第6个字符是:"+str.charAt(5));
    }
}
//第6个字符是:W
  • startsWith函数和endsWith函数:
    • 检测一个字符串是否以指定的字符串开始或结尾
/**
 * 用于测试String中函数特性!
 * @author YiWen Wan
 */
public class StringTest {
   
    public static void main(String[] args) {
   
        String str = "HelloWorld";
        if (str.startsWith("Hello"))
            System.out.println("该字符串是以Hello开始的!");
        if (str.endsWith("World"))
            System.out.println("该字符串是以World结尾的!");

    }
}
//该字符串是以Hello开始的!
//该字符串是以World结尾的!
  • toUpperCase函数和toLowerCase函数:
    • 将原字符串扎转化为全大写或者全小写
/**
 * 用于测试String中函数特性!
 * @author YiWen Wan
 */
public class StringTest {
   
    public static void main(String[] args) {
   
        String str = "HelloWorld";
        System.out.println(str.toUpperCase());
        System.out.println(str.toLowerCase());
    }
}
//HELLOWORLD
//helloworld
  • String.valueOf函数:
    • 一组重载的静态方法,将给定的内容转化为字符串
/**
 * 用于测试String中函数特性!
 * @author YiWen Wan
 */
public class StringTest {
   
    public static void main(String[] args) {
   
        int a = 10;
        double b = 3.14;
        char c = 'c';
        float d = 3.145f;
        System.out.println(String.valueOf(a));
        System.out.println(String.valueOf(b));
        System.out.println(String .valueOf(c));
        System.out.println(String.valueOf(d));
        //更加简单的方法,但是效率不高
        String str = 10+"";
        System.out.println("更加简单的方法:"+str);
        //一个小测试
        System.out.print("测试结果为:");
        System.out.println(1+2);
        System.out.print("测试结果为:");
        System.out.println(1+"2");
    }
}
//        10
//        3.14
//        c
//        3.145
//        更加简单的方法:10
//        测试结果为:3
//        测试结果为:12

五、正则表达式:
①正则表达式简介:
  • 在实际开发中,经常需要对字符串数据进行一些复杂的匹配、查找、替换等操作。通过正则表达式可以方便的实现字符串的复杂操作。

  • 正则表达式是一串特定字符,组成的一个“规则字符串”,这个“规则字符串”是描绘文本规则的工具。正则表达式就是记录文本规则的代码。

  • 字符集合

    • [ ]表示一个字符,具体表示什么,要看里面的内容。
正则表达式 说明
[abc] a、b、c中的任意一个字符
[^abc] 除了a、b、c的任意一个字符
[a-z] a、b、c、……、z中的任意一个字符
[a-zA-Z0-9] a ~ z、A ~ Z、0 ~ 9中的任意一个字符
[a-z &&[ ^ bc]] a ~ z中除了b和c以外的任意一个字符,其中&&表示“与”的关系
  • 预定义字符
    • 类似于Java中的转义字符。
正则表达式 说明
· 任意一个字符
\d 任意一个数字字符,相当于[0-9]
\w 单词字符,相当于[a-zA-Z0-9]
\s 空白字符,相当于[\t\n\x0B\f\r]
\D 非数字字符
\W 非单词字符
\S 非空白字符
  • 数量词
正则表达式 说明
X? 表示0个或1个X
X* 表示0个或任意个X
X+ 表示1个到任意个X
X{n} 表示n个X
X{n,} 表示n个到任意个X
X{n,m} 表示n个到m个X
  • 分组“()”

    • ()圆括号表示分组,可以将一系列的正则表达式看作一个整体,分组时可以使用 “|” 表示 “或” 的关系。
      • 例如:abcabcabc = (abc){3};将abc看做一个整体进行重复。
      • 例如:匹配收集号码前面的区号:(\ +86|0086)?\s?\d{11},圆括号表示这里需要出现“+86”或者“0086”。
  • " ^ “和” $ "

    • 没有这两个边界字符时,正则表达式是部分匹配。
      • 没有这两个边界字符时,正则表达式是部分匹配,部分字符串满足条件就行;单独的" ^ “只看开头是否匹配,单独的” $ "只看结尾是否匹配;当两个一起使用时,才是完全匹配。
    • **例如:**匹配用户名规则——从头到尾连续8~10个单词字符
      • \w{8,10}
        • 如果使用这种写法,则“abcd1234_abcd”是可以验证通过的。
      • ^\w{8,10}$
        • 如果使用这种写法,需要待检验字符串需要完全匹配,此时“abcd1234_abcd”是无法验证通过的。
    • 但是在Java中,就算你不写边界符号,也是会自动加上去的,所以Java默认是全匹配!
②String类中有关于正则表达式的方法:
  • matches方法
    • 判断当前字符串是否符合提供的正则表达式!matches方法指定的正则表达式就算不指定边界匹配符,也是做全匹配验证的!

    • boolean matches(String regex)

/**
 * 用于验证Java中正则表达式的使用!
 * @author YiWen Wan
 */
public class StringTest {
   
    public static void main(String[] args) {
   
        String email = "2000114@WYW.com.cn";//书写输入数据
        /*
        原本的正则表达式是:\w+@\w+(\.[a-zA-z]+)+但是因为Java中表示转义字符也是使用‘\’来表示,但是式子中的‘\’并非表示Java中的转义;
        所以应该让Java看来是一个单纯的‘\’,所以在‘\’前面再加上一个‘\’用来表示!
         */
        String regex = "\\w+@\\w+(\\.[a-zA-z]+)+";//书写正则表达式
        //matches函数用于验证该字符串是否属于正则表达式!
        boolean b = email.matches(regex);
        if (b)
            System.out.println("这是一个邮箱地址!");
        else
            System.out.println("这不是一个邮箱地址!");
    }
}
//这是一个邮箱地址!
  • split方法
    • 使用给定的正则表达式来拆分当前字符串,并且将拆分之后的内容以字符串数组的方法返回
    • String[ ] split(String regex)
/**
 * 用于验证Java中正则表达式的使用!
 * @author YiWen Wan
 */
public class StringTest {
   
    public static void main(String[] args) {
   
        String str = "WYW:007Hello123The456World78765867!";
        //正则表达式(以数字进行分割):[0-9]+或者\d+
        String regex = "\\d+";
        String[] array = str.split(regex);
        System.out.println(Arrays.toString(array));
    }
}
//[WYW:, Hello, The, World, !]
  • 一个有意思的特性:当多次匹配到同一个正则表达式时,将会出现什么样的情况!
/**
 * 用于验证Java中正则表达式的使用!
 * @author YiWen Wan
 */
public class StringTest {
   
    public static void main(String[] args) {
   
        String str = "WYW:007Hello123The456World78765867";
        String regex = "\\d";//此时遇到一次数字拆分一次!
        String[] array = str.split(regex);
        System.out.println(Arrays.toString(array));
    }
}
//[WYW:, , , Hello, , , The, , , World]
  • 会在中间出现"",一个空的字符串!而且如果在开始或者中间连续匹配时,就会出现空串;但是在末尾出现时,就不会出现空串!
/**
 * 用于验证Java中正则表达式的使用!
 * @author YiWen Wan
 */
public class StringTest {
   
    public static void main(String[] args) {
   
        String regex = "\\d";//此时遇到一次数字拆分一次!
        String str = "534534WYW007Hello123The456World7876";
        String[] array = str.split(regex);
        System.out.println(Arrays.toString(array));
    }
}
//[, , , , , , WYW, , , Hello, , , The, , , World]
  • replaceAll方法
    • 将当前字符串中符合正则表达式要求部分的内容转换为给定内容!
    • String replaceAll(String regex,String str)
/**
 * 用于验证Java中正则表达式的使用!
 * @author YiWen Wan
 */
public</
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值